SpringMVC的使用
之前我们介绍了如何创建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类型的异常会执行该方法,并异常对象传递给该方法的参数。
@ResponseBody
public String handlerException(Exception e){
System.out.println(e.getMessage());
return "error";//经过视图解析器: /views/error.jsp
}
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public 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和密钥key
DefaultCredentialProvider 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.jpg
PutObjectResult 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路径即可。