SpringMVC学习
响应数据和结果视图
返回值分类
返回字符串
-
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
@RequestMapping(value="/hello") public String sayHello() { System.out.println("Hello SpringMVC!!"); // 跳转到XX页面 return "success"; }
-
具体的应用场景
@Controller @RequestMapping("/user") public class UserController { /** * 返回String * @param model * @return */ @RequestMapping("/testString") public String testString(Model model){ System.out.println("testString方法执行了..."); // 模拟从数据库中查询出User对象 User user = new User(); user.setUsername("美美"); user.setPassword("123"); user.setAge(30); // model对象 model.addAttribute("user",user); return "success"; } }
返回值是void
-
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
- 默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
-
可以使用请求转发或者重定向跳转到指定的页面
/** * 是void * 请求转发一次请求,不用编写项目的名称 */ @RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("testVoid方法执行了..."); // 编写请求转发的程序 // request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); // 重定向 // response.sendRedirect(request.getContextPath()+"/index.jsp"); // 设置中文乱码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); // 直接会进行响应 response.getWriter().print("你好"); return; }
返回值是ModelAndView对象
-
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
/** * 返回ModelAndView * @return */ @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ // 创建ModelAndView对象 ModelAndView mv = new ModelAndView(); System.out.println("testModelAndView方法执行了..."); // 模拟从数据库中查询出User对象 User user = new User(); user.setUsername("小凤"); user.setPassword("456"); user.setAge(30); // 把user对象存储到mv对象中,也会把user对象存入到request对象 mv.addObject("user",user); // 跳转到哪个页面 mv.setViewName("success"); return mv; }
SpringMVC框架提供的转发和重定向
-
forward请求转发
- controller方法返回String类型,想进行请求转发也可以编写成
/** * 使用关键字的方式进行转发或者重定向 * @return */ @RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect方法执行了..."); 请求的转发 return "forward:/WEB-INF/pages/success.jsp"; }
-
redirect重定向
-
controller方法返回String类型,想进行重定向也可以编写成
/** * 使用关键字的方式进行转发或者重定向 * @return */ @RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect方法执行了..."); // 重定向 return "redirect:/index.jsp"; }
-
ResponseBody响应json数据
-
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
-
mvc:resources标签配置不过滤
-
location元素表示webapp目录下的包下的所有文件
-
mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
<!--前端控制器,哪些静态资源不拦截--> <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/js/" mapping="/js/**"/>
-
-
使用@RequestBody获取请求体数据
<script> // 页面加载,绑定单击事件 $(function(){ $("#btn").click(function(){ // alert("hello btn"); // 发送ajax请求 $.ajax({ // 编写json格式,设置属性和值 url:"user/testAjax", contentType:"application/json;charset=UTF-8", data:'{"username":"hehe","password":"123","age":30}', dataType:"json", type:"post", success:function(data){ // data服务器端响应的json的数据,进行解析 alert(data); alert(data.username); alert(data.password); alert(data.age); } }); }); }); </script>
-
使用@ResponseBody注解把JavaBean对象转换成json字符串,直接响应
-
要求方法需要返回JavaBean的对象
/** * 模拟异步请求响应 */ @RequestMapping("/testAjax") public @ResponseBody User testAjax(@RequestBody User user){ System.out.println("testAjax方法执行了..."); // 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中 System.out.println(user); // 做响应,模拟查询数据库 user.setUsername("haha"); user.setAge(40); // 做响应 return user; }
-
json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
```xml
<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>
```
SpringMVC实现文件上传
SpringMVC传统方式文件上传
-
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同。
-
代码:
/** * SpringMVC文件上传 * @return */ @RequestMapping("/fileupload2") public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception { System.out.println("springmvc文件上传..."); // 使用fileupload组件完成文件上传 // 上传的位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); // 判断,该路径是否存在 File file = new File(path); if(!file.exists()){ // 创建该文件夹 file.mkdirs(); } // 说明上传文件项 // 获取上传文件的名称 String filename = upload.getOriginalFilename(); // 把文件的名称设置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid+"_"+filename; // 完成文件上传 upload.transferTo(new File(path,filename)); return "success"; }
-
配置文件解析器对象
<!--配置文件解析器对象,要求id名称必须是multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760" /> </bean>
SpringMVC跨服务器方式文件上传
-
搭建图片服务器
- 根据文档配置tomcat9的服务器,现在是2个服务器
- 导入image项目,作为图片服务器使用
-
实现SpringMVC跨服务器方式文件上传
- 导入开发需要的jar包
<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>
-
编写文件上传的JSP页面
<h3>跨服务器文件上传</h3> <form action="/user/fileupload3" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload" /><br/> <input type="submit" value="上传" /> </form>
-
编写控制器
/** * 跨服务器文件上传 * @return */ @RequestMapping("/fileupload3") public String fileuoload3(MultipartFile upload) throws Exception { System.out.println("跨服务器文件上传..."); // 定义上传文件服务器路径 String path = "http://localhost:9090/uploads/"; // 说明上传文件项 // 获取上传文件的名称 String filename = upload.getOriginalFilename(); // 把文件的名称设置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid+"_"+filename; // 创建客户端的对象 Client client = Client.create(); // 和图片服务器进行连接 WebResource webResource = client.resource(path + filename); // 上传文件 webResource.put(upload.getBytes()); return "success"; }
SpringMVC的异常处理
异常处理思路
- Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进 行异常的处理。
SpringMVC的异常处理
-
自定义异常类
/** * 自定义异常类 */ public class SysException extends Exception{ // 存储提示信息的 private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public SysException(String message) { this.message = message; } }
-
自定义异常处理器
/** * 异常处理器 */ public class SysExceptionResolver implements HandlerExceptionResolver{ /** * 处理异常业务逻辑 * @param request * @param response * @param handler * @param ex * @return */ public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // 获取到异常对象 SysException e = null; if(ex instanceof SysException){ e = (SysException)ex; }else{ e = new SysException("系统正在维护...."); } // 创建ModelAndView对象 ModelAndView mv = new ModelAndView(); mv.addObject("errorMsg",e.getMessage()); mv.setViewName("error"); return mv; } }
-
配置异常处理器
<!--配置异常处理器--> <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
SpringMVC框架中的拦截器
拦截器的概述
- SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链 中的拦截器会按着定义的顺序执行。
- 拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
- 拦截器也是AOP思想的一种实现方式
- 想要自定义拦截器,需要实现HandlerInterceptor接口。
自定义拦截器步骤
-
创建类,实现HandlerInterceptor接口,重写需要的方法
/** * 自定义拦截器 */ public class MyInterceptor1 implements HandlerInterceptor{ /** * 预处理,controller方法执行前 * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法 * return false不放行 * @param request * @param response * @param handler * @return * @throws Exception */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor1执行了...前1111"); // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); return true; } /** * 后处理方法,controller方法执行后,success.jsp执行之前 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor1执行了...后1111"); // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); } /** * success.jsp页面执行后,该方法会执行 * @param request * @param response * @param handler * @param ex * @throws Exception */ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyInterceptor1执行了...最后1111"); } }
-
在springmvc.xml中配置拦截器类
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法
<mvc:exclude-mapping path=""/>
-->
<!--配置拦截器对象-->
<bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor1" />
</mvc:interceptor>
</mvc:interceptors>
HandlerInterceptor接口中的方法
- preHandle方法是controller方法执行前拦截的方法
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
- postHandle是controller方法执行后执行的方法,在JSP视图执行前。
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
- postHandle方法是在JSP执行后执行
- request或者response不能再跳转页面了
配置多个拦截器
-
再编写一个拦截器的类
** * 自定义拦截器 */ public class MyInterceptor2 implements HandlerInterceptor{ /** * 预处理,controller方法执行前 * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法 * return false不放行 * @param request * @param response * @param handler * @return * @throws Exception */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor1执行了...前2222"); // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); return true; } /** * 后处理方法,controller方法执行后,success.jsp执行之前 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyInterceptor1执行了...后2222"); // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); } /** * success.jsp页面执行后,该方法会执行 * @param request * @param response * @param handler * @param ex * @throws Exception */ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyInterceptor1执行了...最后2222"); } }
-
配置2个拦截器
<!--配置拦截器--> <mvc:interceptors> <!--配置拦截器--> <mvc:interceptor> <!--要拦截的具体的方法--> <mvc:mapping path="/user/*"/> <!--不要拦截的方法 <mvc:exclude-mapping path=""/> --> <!--配置拦截器对象--> <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor1" /> </mvc:interceptor> <!--配置第二个拦截器--> <mvc:interceptor> <!--要拦截的具体的方法--> <mvc:mapping path="/**"/> <!--不要拦截的方法 <mvc:exclude-mapping path=""/> --> <!--配置拦截器对象--> <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor2" /> </mvc:interceptor> </mvc:interceptors>