springMVC笔记(二)
1 响应数据和结果视图
1.1返回值分类
1.1.1字符串
controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
/** * 返回值为String * @param model * @return */ //指定逻辑视图名,经过视图解析器解析为 jsp 物理路径:/WEB-INF/pages/success.jsp @RequestMapping("/testString") public String testString(Model model){ System.out.println("testString执行了..."); //模拟从数据库中查询出user对象 User user = new User(); user.setUsername("小明"); user.setAge(234); user.setPassword("123143"); //model对象 model.addAttribute("user",user); return "success"; } <a href="user/testString">testString</a>
1.1.2 void
@RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("testVoid执行了..."); //1.编写请求转发的程序,手动写转发时,容器不会再用视图解析器,所以需要自己写路径 //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); //2.重定向 // response.sendRedirect(request.getContextPath()+"/index.jsp"); //设置中文乱码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); //3.直接回进行响应 response.getWriter().print("小名sdf"); return; //结束程序 }
1.1.3ModelAndView
ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值。 该对象中有两个方法:
/** * 返回ModelAndView * @return */ @RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ //创建ModelAndView对象 ModelAndView mv = new ModelAndView(); System.out.println("testModelAndView执行了..."); //模拟从数据库中查询出user对象 User user = new User(); user.setUsername("小刚"); user.setAge(8); user.setPassword("110110"); //把user对象数据存储到mv对象中,也会把user对象存入到request对象 mv.addObject("user",user); //跳转到多个页面 mv.setViewName("success"); return mv; }
我们在页面上上获取使用的是user.name 取的,所以返回 ModelAndView 类型时,浏 览器跳转只能是请求转发
1.2转发和重定向
1.2.1forward转发
controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。我们也可以写成:
/** * 使用关键字的方式进行转发或者重定向 * @return */ @RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect执行了..."); //请求转发 return "forward:/WEB-INF/pages/success.jsp"; //重定向 //请求不到/WEB-INF/pages/success.jsp,且底层帮我们加了项目名 //return "redirect:/index.jsp"; }
需要注意的是,如果用了 formward:则路径必须写成实际视图 url,不能写逻辑视图。 它相当于“request.getRequestDispatcher("url").forward(request,response)”。使用请求 转发,既可以转发到 jsp,也可以转发到其他的控制器方法。
1.2.2Redirect重定向
contrller 方法提供了一个 String 类型返回值之后,它需要在返回值里使用:redirect:
/** * 使用关键字的方式进行转发或者重定向 * @return */ @RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect执行了..."); //请求转发 //return "forward:/WEB-INF/pages/success.jsp"; //重定向 //请求不到/WEB-INF/pages/success.jsp,且底层帮我们加了项目名 return "redirect:/index.jsp"; }
它相当于“response.sendRedirect(url)”。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不 能写在 WEB-INF 目录中,否则无法找到。
1.3RequestBody响应json数据
1.3.1使用说明
作用: 该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的 数据如:json,xml 等,通过 Response 响应给客户端
1.3.2使用示例
需求: 使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端。
前置知识点: Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入 jackson 的包。
<script src="js/jquery.min.js"></script> <script> //页面加载,绑定单击事件 $(function(){ $("#btn").click(function(){ //alert("hello btn"); //编写ajax格式,设置属性和值 $.ajax({ url:"user/testAjax", contentType: "application/json;charset=UTF-8", data:'{"username":"hehe","password":"123143"}', dataType:"json", type:"post", success:function (data) { //data服务端响应的json的数据,进行解析 alert(data); alert(data.username); alert(data.password); alert(data.age); } }) }); }); </script> </head> <body> <button id="btn">发送ajax的请求</button> /** * 模拟异步请求响应 */ @RequestMapping("/testAjax") public @ResponseBody User testAjax(@RequestBody User user){ System.out.println("testAjax执行了..."); //客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中 System.out.println(user); //作响应,模拟查询数据库 user.setUsername("ashklfjda"); user.setAge(324); //作响应 return user; }
2SpringMVC实现文件上传
文件上传的必要前提
A form 表单的 enctype 取值必须是:multipart/form-data
(默认值是:application/x-www-form-urlencoded)
enctype:是表单请求正文的类型
B method 属性取值必须是 Post
C 提供一个文件选择域
2.1传统的Javaweb上传方式
<h3>传统javaWeb文件上传</h3> <form action="user/fileupload1" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传"/> </form> /** * 文件上传,传统的javaWeb方式 * @return */ @RequestMapping("/fileupload1") public String fileupload1(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("文件上传..."); //使用fileupload组件完成文件上传 //上传位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); //判断,该路径是否存在 System.out.println(path); File file = new File(path); if(!file.exists()){ //创建该文件夹 file.mkdirs(); } //解析request对象,获取上传文件项 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); //解析request List<FileItem> items = upload.parseRequest(request); //遍历 for(FileItem item:items){ //进行判断,当前item对象是否上传文件项 if(item.isFormField()){ //说明普通表单项 }else{ //说明上传文件项 //获取上传文件的名称 String filename = item.getName(); //把文件的名称设置为唯一值,UUID String uuid = UUID.randomUUID().toString().replace("-",""); filename =uuid+"_"+filename; System.out.println(filename); //完成文件上传 item.write(new File(path,filename)); //删除临时文件 item.delete(); } } return "success"; }
2.2 springmvc 传统方式的文件上传
导包:
<h3>springMVC文件上传</h3> <form action="user/fileupload2" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传"/> </form> /** * 文件上传,springMVC方式 * @return */ @RequestMapping("/fileupload2") public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception { System.out.println("springMVC文件上传..."); //使用fileupload组件完成文件上传 //上传位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); //判断,该路径是否存在 System.out.println(path); File file = new File(path); if(!file.exists()){ //创建该文件夹 file.mkdirs(); } //说明上传文件项 //获取上传文件的名称 String filename = upload.getOriginalFilename(); //把文件的名称设置为唯一值,UUID String uuid = UUID.randomUUID().toString().replace("-",""); filename =uuid+"_"+filename; System.out.println(filename); //5.使用 MulitpartFile 接口中方法,把上传的文件写到指定位置 upload.transferTo(new File(path,filename)); return "success"; }
配置文件解析器
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" <!-- id 的值是固定的--> class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为 5MB 5*1024*1024-->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
注意: 文件上传的解析器 id是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他 字段也将无法绑定
2.3springmvc跨服务器方式的文件上传
2.3.1分服务器的目的
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
(注意:此处说的不是服务器集群)
3.2.2准备两个 tomcat 服务器,并创建一个用于存放文件的 web 工程
3.2.3编写控制器实现上传图片
/** * 文件上传,跨服务器方式 * @return */ @RequestMapping("/fileupload3") public String fileupload3(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; System.out.println(filename); //完成文件上传,跨服务器上传 //创建客服端的对象 Client client = Client.create(); //和图片文件进行连接 WebResource webResource = client.resource(path + filename); //上传文件 webResource.put(upload.getBytes()); return "success"; } <h3>跨服务器文件上传</h3> <form action="user/fileupload3" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传"/> </form>
springMVC-returned a response status of 400 OR 403 OR 409
3SpringMVC中的异常处理
3.1异常处理的思路
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息, 后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端 控制器交由异常处理器进行异常处理,如下图:
3.2实现步骤
3.2.1编写异常类和错误页面
3.2.2自定义异常处理
/** * 异常处理器 */ public class SysExceptionResolver implements HandlerExceptionResolver { /** * 处理异常业务逻辑 * @param Request * @param Response * @param handler * @param ex * @return */ @Override 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; } }
3.2.3配置异常处理器
3.2.4运行结果
4SpringMVC中的拦截器
4.1拦截器作用
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺 序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦 截的。
它也是 AOP 思想的具体应用。 我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口
4.2自定义拦截器的步骤
4.2.1第一步:编写一个普通类实现 HandlerInterceptor 接口
/** * 自定义拦截器 */ public class MyInterceptor1 implements HandlerInterceptor { /** * 预处理,controller方法执行前 * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法 * return false 不放行 * 如何调用: * 按拦截器定义顺序调用 * 何时调用: * 只要配置了都会调用 * 有什么用: * 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 * 进行处理,则返回 true。 * 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyInterceptor1执行了..."); //指定跳转页面 //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); return true; } /** * 后处理方法,controller方法执行后,success.jsp执行之前 如何调用: * 按拦截器定义逆序调用 * 何时调用: * 在拦截器链内所有拦截器返成功调用 * 有什么用: * 在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用, * 在该方法中对用户请求 request 进行处理。 * @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("MyInterceptor1执行了....后"); //指定跳转页面 // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); } /** * success.jsp页面执行后,该方法会执行 * 如何调用: * 按拦截器定义逆序调用 * 何时调用: * 只有 preHandle 返回 true 才调用 * 有什么用: * 在 DispatcherServlet 完全处理完请求后被调用, * 可以在该方法中进行一些资源清理的操作。 * @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("MyInterceptor1执行了....最后"); } }
4.2.2第二步:配置拦截器
<!-- 配置拦截器-->
<mvc:interceptors>
<!-- 配置拦截器-->
<mvc:interceptor>
<!-- 要拦截的具体的方法-->
<mvc:mapping path="/user/*"/><!--用于指定对拦截的 url -->
<!-- 不要拦截的方法-->
<!-- <mvc:exclude-mapping path=""/>><!--用于指定排除的 url--> -->
<!-- 配置拦截器对象-->
<bean class="com.springmvc.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
4.2.3 测试运行结果
4.3多个拦截器
4.3.1第一步:编写多个普通类实现 HandlerInterceptor 接口
4.3.1第二步:配置拦截器
4.3.3 测试运行结果