之前我们介绍了如何创建SpringMVC工程,本期介绍如何如何更加详细的使用SpringMVC。
这里给出之前的链接:如何创建SpringMVC工程-CSDN博客
1.跳转不经过视图解析器
之前我们为SpringMVC工程添加了视图解析器,使得每个返回的字符串请求都会加上前缀和后缀。
如果想要不经过视图解析器,可以使用redirect和forward关键字告诉springMVC无需经过视图解析器。
2.controller保存数据的方式
controller层也就是网络请求服务,我们可以通过在方法中添加request接口参数,将数据保存到本次请求中。
springMVC也提供了一个Model对象,该对象的保存周期默认和request等价。如果想要改变保存周期为会话周期需要添加注解@SessionAttributes("键"),键的值为model添加的值。
或者我们直接在方法的参数中引入session对象,将数据直接保存到session对象中。
3.返回json对象
当前端使用ajax请求后端服务器时,我们可以通过查询数据库的数据后将数据以json格式返回到前端,这样前端只需要将数据展示出来就可以,不用等待服务器的响应。
1.首先需要引入依赖jackson
<!--jackson--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.18.1</version></dependency>
2.在方法上使用@ResponseBody注解
3.前端发送ajax请求
<body><button onclick="submit()">提交</button>
</body>
<script>function submit(){$.get("/list",function(data){console.log(data);//浏览器控制台输出},"json")}
</script>
4.拦截器的使用
拦截器可以帮助我们拦截请求而不会拦截静态页面和资源。想要使用拦截器需要定义一个拦截器类并实现拦截器接口。
public class MyInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取session对象HttpSession session=request.getSession();//获取session当前用户的信息Object userinfo = session.getAttribute("userinfo");if(userinfo==null){//没有登录,跳转到登录页面response.sendRedirect("/login.jsp");return false;}return true; //如果返回值为true,表示拦截器放行。否则,拦截器不放行}
}
然后需要在springmvc的配置文件中添加拦截器的配置标签:
<!--注册自定义拦截器以及拦截规则--><mvc:interceptors><mvc:interceptor><!--path:拦截的路径 /**表示拦截多层路径,这样不会拦截/login,/register等单层路径--><mvc:mapping path="/**"/><!--排除的路径。--><mvc:exclude-mapping path="/user/login"/><!--放置自定义的拦截器类--><bean class="com.aaa.interceptor.MyInterceptor"/></mvc:interceptor></mvc:interceptors>
5.全局异常处理
如果controller层发生异常,可以定义一个全局异常类用于处理请求出现的问题,这样对于所有异常都有一个统一的处理方法。
我们需要确保这个类能够被springmvc扫描器扫描到。
这个类捕获优先执行异常范围更为精确的异常,对于不同异常执行的顺序不由它们的位置决定。
//全局异常处理类.
@ControllerAdvice
public class MyGlobalException {@ExceptionHandler(Exception.class) //当发生Exception类型的异常会执行该方法,并异常对象传递给该方法的参数。@ResponseBodypublic String handlerException(Exception e){System.out.println(e.getMessage());return "error";//经过视图解析器: /views/error.jsp}@ExceptionHandler(ArithmeticException.class)@ResponseBodypublic String handlerArithmeticException(Exception e){System.out.println("算数错误");return "error";}}
如果前端使用的是ajax,那么可以接收到错误信息。
function loadEmp(){$.ajax({url:"/emp/list",type:"get",dataType:"json",//服务器响应成功success:function(data){console.log(data)var str="";for(var i=0;i<data.length;i++){str+="<tr>"str+="<td>"+data[i].empId+"</td>"str+="<td>"+data[i].empName+"</td>"str+="</tr>"}document.getElementById("empBody").innerHTML=str;},//服务器响应故障,这个用来接收异常请求error: function (data){console.log(data);}})}
6.上传本地文件
在我们浏览网页时,通常都会有上传图片或文件的功能,例如我们上传一张头像后,前端就显示了我们所上传的图像图片。想要实现文件上传的功能需要以下几个步骤:
1.引入文件上传的依赖
<!--文件上传依赖--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.5</version></dependency>
2.在spring配置文件中上传解析器
<!--文件上传解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!--最大上传的大小。单位byte字节。5M=5*1024*1024--><property name="maxUploadSize" value="5242880"/><!--设置文件上传的编码--><property name="defaultEncoding" value="utf-8"/></bean>
3.前端编写能够提交文件的代码
<%--文件上传的表单提交方式必须为post.而且需要设置表单提交的编码格式。enctype="multipart/form-data" 该类型表示既能上传文本又能上传文件。--%><form action="/upload" method="post" enctype="multipart/form-data">选择文件:<input type="file" name="myfile"/><br>姓名:<input type="text" name="username"/><br><input type="submit"/></form>
4.编写存储到本地的接口
springmvc提供了一个transferTo的方法,可以将文件存储到本地服务器下。
@RequestMapping("/upload")public String upload(MultipartFile myfile, HttpServletRequest request) throws IOException {//1.获取保存文件的路径String realPath = request.getSession().getServletContext().getRealPath("/images");//2.根据上面的路径创建文件对象File file=new File(realPath);//3.判断该文件夹是否存在if(!file.exists()){file.mkdirs();}//4.获取上传文件的名称. 获取登录者ip+登录者id+登录者的时间戳String filename = UUID.randomUUID().toString().replace("-","")+myfile.getOriginalFilename();//5.把上传的文件保存到指定服务器下的路径。File target=new File(realPath+"/"+filename);myfile.transferTo(target);System.out.println("上传成功");return "main";}
5.阿里云服务器的使用
在实际编写代码中,一般除了公司配置了专门的服务器,其余大都是通过第三方文件服务器存储客户上传的文件。这里我使用的是阿里云的OSS存储。
首先需要登录阿里云。官网地址:阿里云-计算,为了无法计算的价值 。
如果之前没有注册过阿里云需要先注册账号,然后我们在上方的产品导航栏中找到对象存储OSS,点击进入。
如果之前没有开通过对象存储OSS服务,需要点击立即开通。之后会出现如下界面。
点击管理控制台后,会进入新的界面。这里我们找到Bucket列表,然后选择创建Bucket。
创建有许多选项,这里根据个人需求选择,部分选项可能会带来额外的收费。
创建完Bucket后我们还需要去申请密钥,密钥是用来连接阿里云服务的唯一凭证,需要妥善保管。将鼠标移至头像处有一个Accesskey,在这里可以进入到密钥处。
进入后看到左上角有一个创建AccessKey。点击即可,之后需要进行验证, 完成后会给一个文件,里面填写者密钥的id和key。密钥同时最多只能持有三个,需要妥善管理。
之后我们就能够开始进行代码的编写了,这里阿里云给我们提供好了基础的代码,我们只需要在此基础上进行更改即可。
回到主界面找到产品文档,点击进入。
找到开发参考下的SDK参考,选择java。点击快速入门。
里面有许多说明,可以根据自己的开发需求进行阅读。这里我使用了maven工程,所以直接引入依赖。
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version>
</dependency><!--如果使用的是Java 9及以上的版本,则需要添加以下JAXB相关依赖。--><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version>
</dependency>
<dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.3</version>
</dependency>
然后选择Java下的,对象/文件下的 简单上传,在里面找到文件上传。
下方代码展示了如何上传基础的文件。其中有一些参数需要进行解释。
- endpoint为地域节点,需要填写您实际申请的地域地址。地域节点可以点击bucket名称中的概述中找到地域节点填写。
- bucketName为您创建Bucket时所起的名字。
- credentialsProvider 为您申请的密钥Id 和 key 的访问凭证申请。
- objectName为您想要上传文件的名称。
- filePath为您想要上传文件所存放的地址。
- region为您申请bucket的所在地域。
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.File;public class Demo {public static void main(String[] args) throws Exception {// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = "exampledir/exampleobject.txt";// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。String filePath= "D:\\localpath\\examplefile.txt";// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。String region = "cn-hangzhou";// 创建OSSClient实例。ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); OSS ossClient = OSSClientBuilder.create().endpoint(endpoint).credentialsProvider(credentialsProvider).clientConfiguration(clientBuilderConfiguration).region(region) .build();try {// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。// ObjectMetadata metadata = new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传文件。PutObjectResult result = ossClient.putObject(putObjectRequest); } catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
}
这样已经可以上传指定位置的文件了,但如果想要根据前端用户上传的文件进行存放,需要对这段代码进行改造。这里我将其编写成了一个方法,可以用来传入文件。并返回该文件的网络地址。
这里返回的网络地址,是根据上传文件生成的URL拼接得来的。
public class AliyunConnection {public String uploadOss(MultipartFile file) {// 其它Region请按实际情况填写。我填写的是北京String endpoint = "oss-cn-beijing.aliyuncs.com";// 这里我改成了默认输入密钥ID和密钥keyDefaultCredentialProvider defaultCredentialProvider = CredentialsProviderFactory.newDefaultCredentialProvider("密钥ID", "密钥key");// 填写Bucket名称,例如examplebucket。String bucketName = "bucket名称";// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。String objectName = UUID.randomUUID().toString().replaceAll("-","") + file.getOriginalFilename();// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。// 填写Bucket所在地域。String region = "cn-beijing";// 创建OSSClient实例。ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);OSS ossClient = OSSClientBuilder.create().endpoint(endpoint).credentialsProvider(defaultCredentialProvider).clientConfiguration(clientBuilderConfiguration).region(region).build();try {InputStream inputStream = file.getInputStream();// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。// ObjectMetadata metadata = new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传文件。//https://createdreamchen.oss-cn-beijing.aliyuncs.com/96c29d54034241d6aff3923dbb34e31d1.jpgPutObjectResult result = ossClient.putObject(putObjectRequest);return "http://"+ bucketName + "." + endpoint + "/" + objectName;} catch (OSSException oe) {throw new OSSException("OSS错误");} catch (ClientException ce) {throw new ClientException(ce);} catch (IOException e) {throw new RuntimeException(e);} finally {if (ossClient != null) {ossClient.shutdown();}}}
}
至此,就完成了上传本地文件的所有操作。之后可以调用这个方法返回一个string字符串,将其存入数据库中。并在前端获取该文件的url路径即可。