大纲:
1.SpringMVC的响应数据和结果视图
2.SpringMVC文件上传
3.SpringMVC异常处理
4.SpringMVC的拦截器
1.Springmvc的响应数据和结果视图
1.1返回值分类
(1)返回字符串
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址
(2)返回的是void
- 如果控制器的方法返回值编写成void。
默认会跳转到@RequestMapping(value=“/initUpdate”) initUpdate.jsp的页面,跳转到 页面的名称和请求资源名称一样的页面,如果不存在,则会返回404。 - 可以使用请求转发或者重定向跳转到指定的页面
// 请求转发
request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request, response);
// 重定向
response.sendRedirect(request.getContextPath()+"/add2.jsp");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 直接响应数据
response.getWriter().print("你好");
(3)返回值是ModelAndView对象
后端返回ModelAndView代码:
@RequestMapping("/testResponseMdv")
public ModelAndView testResponseMdv(){
ModelAndView modelAndView= new ModelAndView();
modelAndView.setViewName("list");
List<User> users = new ArrayList<>();
User user1 = new User();
user1.setUsername("张三");
User user2 = new User();
user2.setUsername("里斯");
User user3 = new User();
user3.setUsername("王五");
users.add(user1);
users.add(user2);
users.add(user3);
modelAndView.addObject("users",users);
return modelAndView;
}
前端页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>List</title>
</head>
<body>
<h4>LIST</h4>
<h3>查询所有的数据</h3>
<c:forEach items="${ users }"
var="user">
${ user.username }
</c:forEach>
</body>
</html>
2.SpringMVC提供的重定向和转发
2.1 forward请求转发
注意:“forward:转发的JSP路径”,不走视图解析器了,所以需要编写完整的路径
@RequestMapping("/delete")
public String delete() throws Exception {
System.out.println("delete方法执行了...");
// return "forward:/WEB-INF/pages/success.jsp";
return "forward:/user/findAll";
}
2.2 redirect重定向
@RequestMapping("/count")
public String count() throws Exception {
System.out.println("count方法执行了...");
return "redirect:/add.jsp";
// return "redirect:/user/findAll";
}
3.ResponseBody响应json数据(ajax异步请求)
3.1添加maven依赖:jackson
<!--json字符串和JavaBean对象互相转换,需要使用jackson的jar包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
3.2添加js和jquery的依赖
在webapp目录下创建js、jquery目录,添加js和jquery。
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置。
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
3.3后端控制层
/***
* 测试ResponseBody的方法
* @return
*/
@RequestMapping("/testResponseBody")
public @ResponseBody User testResponseBody(){
User user1 = new User();
user1.setUsername("张三");
user1.setPassword("123456");
user1.setDate("2022-05-12");
return user1;
}
3.4前端发送ajax请求
<!--js、jquery是webapp目录下的-->
<script type="text/javascript" src="./js/jquery.min.js" ></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/jquery/jquery-1.12.4.min.js" ></script>
<script type="text/javascript">
$(function () {
$("#testAjaxAndJson").click(function () {
$.ajax( {
"url":"${pageContext.request.contextPath}/testModelAndView/testResponseBody",
"type":"POST",
"contentType":"application/json;charset=utf-8",
"dataType":"json",
"success":function (data,textStatus) {
alert("data:"+ data);
alert("data.username:"+ data.username);
alert("data.password:"+ data.password);
}
});
});
})
</script>
<h5>responsebody测试</h5>
<input type="button" value="测试ajax请求和ResponseBody" id="testAjaxAndJson"/></br>
4.SpringMVC文件上传
4.1文件上传的回顾
(1)添加依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
(2)控制层代码
@Controller
@RequestMapping("/fileUploadController")
public class FileUploadController {
@RequestMapping("/uploadFile1")
public String uploadFile1(HttpServletRequest request) {
try{
String realPath = request.getSession().getServletContext().getRealPath("/downloads");
File file = new File(realPath);
if(!file.exists()){
file.mkdirs();
}
DiskFileItemFactory factory= new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
List<FileItem> fileItems = fileUpload.parseRequest(request);
fileItems.stream().forEach(fileItem -> {
// 判断文件项是普通字段,还是上传的文件
if(fileItem.isFormField()){
}else{
// 上传文件项
//获取上传文件的名称
String filename = fileItem.getName();
String uuid = UUID.randomUUID().toString().replace("-","");
filename=filename+uuid;
try {
fileItem.write(new File(file,filename));
// 删除临时文件
fileItem.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}catch (Exception ex){
ex.printStackTrace();
}
return "success";
}
}
(3)前端文件上传
<form method="post" action="fileUploadController/uploadFile1" enctype="multipart/form-data">
<input type="file" name="uploadfile" />
<input type="submit" value="上传"/>
</form>
4.2SpringMVC传统的文件上传
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单fifile标签的name属性名称相同。
(1)添加依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
(2)控制层代码
@RequestMapping("/uploadFile2")
public String uploadFile2(HttpServletRequest request,MultipartFile uploadfile) {
try{
String realPath = request.getSession().getServletContext().getRealPath("/downloads");
File file = new File(realPath);
if(!file.exists()){
file.mkdirs();
}
// 获取到上传文件的名称
String filename = uploadfile.getOriginalFilename();
filename=UUID.randomUUID().toString().replaceAll("-","").toUpperCase() + "_"+filename;
uploadfile.transferTo(new File(file,filename));
}catch (Exception ex){
ex.printStackTrace();
}
return "success";
}
(3)前端代码
<h5>SpringMVC传统文件上传</h5>
<form method="post" action="fileUploadController/uploadFile2" enctype="multipart/form-data">
<input type="file" name="uploadfile" />
<input type="submit" value="上传"/>
</form>
(4)Springmvc.xml 配置文件上传
<!--配置文件上传-->
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
4.3SpringMVC跨服务器的文件上传
(1)文件服务器配置
文件服务器的web.xml的配置:
<servlet>
<!--首先需要导入:tomcat-catalina-->
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<!--加入此行的含义是:接收文件的目标服务器可以支持写入操作。-->
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(2)文件上传服务器
<1>加入依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!--跨服务器上传文件-->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
<2>后端上传代码
@RequestMapping("/uploadFile3")
public String uploadFile3(HttpServletRequest request,MultipartFile uploadfile) {
try{
String realPath = request.getSession().getServletContext().getRealPath("/downloads");
File file = new File(realPath);
if(!file.exists()){
file.mkdirs();
}
// 获取到上传文件的名称
String filename = uploadfile.getOriginalFilename();
filename=UUID.randomUUID().toString().replaceAll("-","").toUpperCase() + "_"+filename;
//5.创建 sun 公司提供的 jersey 包中的 Client 对象
Client client = Client.create();
//6.指定上传文件的地址,该地址是 web 路径
WebResource resource = client.resource("http://localhost:8090/SpringMVC_fileUploadServer/uploadFiles/"+filename);
//7.实现上传
String result = resource.put(String.class,uploadfile.getBytes());
System.out.println(result);
}catch (Exception ex){
ex.printStackTrace();
}
return "success";
}
<3>前端代码
<h5>SpringMVC跨服务文件上传</h5>
<form method="post" action="fileUploadController/uploadFile3" enctype="multipart/form-data">
<input type="file" name="uploadfile" />
<input type="submit" value="上传"/>
</form>
<4>springmvc.xml配置文件上传
<!--配置文件上传-->
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
5.SpringMVC的异常处理
Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理。
5.1 代码实现
<1>自定义异常CustomeException
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
this.message = message; }
public String getMessage() {
return message;
}
}
<2>自定义异常处理器继承 HandlerExceptionResolver
public class CustomExceptionHandlerResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
e.printStackTrace();
CustomException customException= null;
ModelAndView mdv =new ModelAndView();
if(e instanceof CustomException){
customException = (CustomException)e;
}else{
customException = new CustomException("请联系管理员");
}
mdv.setViewName("fail");
mdv.addObject("errorMsg",e.getMessage());
return mdv;
}
}
<3>配置异常处理器
<!-- 配置异常处理器 -->
<bean id="customExceptionHandlerResolver"
class="com.Eheart.util.CustomExceptionHandlerResolver"/>
6.SpringMVC的拦截器
6.1单个拦截器
拦截器和过滤器的区别:
● 过滤器是Servlet规范的一部分,任何java web都可以使用的。拦截器是SpringMVC的,仅可以mvc使用
● 过滤器路径是 / *,可以对所有的资源过滤,对于js等静态资源需要在配置文件进行不过滤配置。拦截器只会拦截访问控制器的方法,不会拦截js、jquery、html、css等静态资源。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
● HandlerInterceptor接口中的方法
- preHandle方法是controller方法执行前拦截的方法
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
- postHandle是controller方法执行后执行的方法,在JSP视图执行前。
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
- postHandle方法是在JSP执行后执行
- request或者response不能再跳转页面了
1.继承HandlerInterceptor
public class HandlerInterceptorDemo implements HandlerInterceptor {
/**
* 返回值是:false不会放行,为true会放行,先于Controller执行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("HandlerInterceptorDemo1...............preHandle");
return true;
}
/**
*后于Controller执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptorDemo1...............postHandle");
}
/**
* 最后执行,在JSP执行后执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("HandlerInterceptorDemo1...............afterCompletion");
}
}
2.配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="handlerInterceptorDemo1" class="com.Eheart.util.HandlerInterceptorDemo"></bean>
</mvc:interceptor>
</mvc:interceptors>
6.2多个拦截器
多个拦截器执行的流程图:
多个拦截器执行的顺序:
多个拦截器执行的日志输出:
6.3拦截器和过滤器的区别