• springMvc的第三天--文件上传、视图解析器、拦截器、全局异常处理器


    目录

    一、文件上传(多媒体视图解析器)

     1 servlet的文件上传

      2.CommonsMultipartResolver

        1.在spring中配置多媒体视图的解析器

        2.MultipartFile 可以作为请求参数,根据名称会将多媒体组件封装在该类型的参数中

    3.多文件上传 

    二、视图解析器

    三、拦截器(拦截不了jsp页面)

    1 应用场景

    2 过滤器和拦截器的区别

    3步骤

    3.1定义拦截器   实现HandlerInterceptor接口

    3.2将拦截器交给spring管理

    3.3 配置拦截器

     4 拦截器链

    5 无法拦截jsp

    6 拦截jsp的解决方案: 

    7.不拦截静态资源(推荐使用)

    8 应用场景的例子

     1.权限设置(拦截器版本) 

     2.性能监控(监控请求的执行时间和响应时间)

    四、全局异常处理器

    1.步骤 

             1.1 创建类 实现HandlerExceptionResolver接口

    2.2 将类交给spring管理

    2.3 自定义异常

    2.4 方法中抛出异常



    一、文件上传(多媒体视图解析器)

    springmvc多媒视图解析器,快速的使用commons-fileupload进行文件上传,并且简化了传统commons-fileupload文件上传的代码编写

     1 servlet的文件上传

    首先添加 commons-io.jar  commons-fileupload.jar 

    1. //文件上传 手动写
    2. @ResponseBody
    3. @PostMapping("/upload")
    4. public String testLoad(HttpServletRequest request,HttpServletResponse response) throws Exception {
    5. //多媒体enctype 无法使用 requestParameter("")
    6. //创建diskfileitemfactory处理文件的上传路径和大小限制;
    7. DiskFileItemFactory factory =new DiskFileItemFactory();
    8. // factory可选方法
    9. // factory.setSizeThreshold(1024*1024);//factory的set不用写有默认值
    10. // factory.setRepository(tmpFile);//设置临时仓库
    11. //准备完成后创建文件上载对象
    12. ServletFileUpload upload =new ServletFileUpload(factory);
    13. //将发送来的数据表单中的对象通过upload对象解析成FileitemList
    14. List items = upload.parseRequest(request);
    15. //遍历每个List中的对象判断需要上载的文件
    16. User user =new User();
    17. for (FileItem item : items) {
    18. //判断对象是否是表单中的普通类还是文件类
    19. if(item.isFormField()) {
    20. //普通组件
    21. // getFieldName是获得表单中输入框的name
    22. String name=item.getFieldName();
    23. String value=item.getString("UTF-8");//乱码处理
    24. if("userName".equals(name)) {
    25. user.setUserName(value);
    26. }
    27. if("userAge".equals(name)) {
    28. user.setUserAge(Integer.parseInt(value));
    29. }
    30. }else {
    31. //多媒体组件
    32. //获取客户端的文件名称
    33. String fileName =item.getName();
    34. String newFileName =UUID.randomUUID().toString();
    35. //UUID保证名称不同 + 获取文件后面的.后缀
    36. newFileName=newFileName+fileName.substring(fileName.lastIndexOf("."),fileName.length());
    37. //获取到真实路径 d:tomacat/项目名/
    38. String path=request.getRealPath("/");
    39. path=path+"upload/";
    40. File pathFile =new File(path);
    41. //如果不存在就创建
    42. if(!pathFile.exists()) {
    43. pathFile.mkdir();
    44. }
    45. //客户端写入文件
    46. item.write(new File(path+newFileName));
    47. }
    48. }
    49. return "success";
    50. }

     注意:前端的from表单的enctype一定要是 multipart/from-date格式 

    1. <%@ page language="java" contentType="text/html; charset=UTF-8"
    2. pageEncoding="UTF-8"%>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <script src="js/jquery-3.6.0.js">script>
    8. <link rel="stylesheet" href="css/css1.css">
    9. <title>Insert title heretitle>
    10. head>
    11. <body>
    12. <form action="upload" method="POST" enctype="multipart/form-data">
    13. 用户名称 <input type="test" name="userName" /> <br>
    14. 年龄用户 <input type="test" name="userAge" /> <br>
    15. 身份照片<input type="file" name="cord" /> <br>
    16. <input type="submit" value="保存" />
    17. form>
    18. body>
    19. html>

        问题
           
    1.需要手动创建工厂并手动解析请求 

           2.非多媒体类型的请求  参数因为enctype的改变  ,导致传统的获取方式不能使用(即 request.parameter)

          3.并且不能进行请求参数的封装

      2.CommonsMultipartResolver

        1.在spring中配置多媒体视图的解析器

       

    1. <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    2. <property name="defaultEncoding" value="UTF-8" >property>
    3. <property name="maxUploadSize" value="-1">property>
    4. bean>

      2.MultipartFile 可以作为请求参数,根据名称会将多媒体组件封装在该类型的参数中

    1. @ResponseBody
    2. @PostMapping("/upload2")
    3. //MultipartFile 可以作为请求参数 ,根据名称会将多媒体组件封装在该类型的参数中
    4. //名字与前端的 file的name相同
    5. public String testLoad2(MultipartFile cord ,User user,HttpServletRequest request,HttpServletResponse response) throws Exception {
    6. String fileName =cord.getOriginalFilename();
    7. String newFileName=UUID.randomUUID().toString();
    8. newFileName=newFileName+fileName.substring(fileName.lastIndexOf("."),fileName.length());
    9. String path=request.getRealPath("/");
    10. path=path+"upload/";
    11. File filePath=new File(path);
    12. //如果不存在就进行创建
    13. if(!filePath.exists()) {
    14. filePath.mkdir();
    15. }
    16. //写入
    17. cord.transferTo(new File(path+newFileName));
    18. return "success";
    19. }

    3.多文件上传 

      多文件上传时,即使组件的名称和形参的名称一致,也需要增加@RequestParame

    1. @ResponseBody
    2. @PostMapping("/upload2")
    3. //MultipartFile 可以作为请求参数 ,根据名称会将多媒体组件封装在该类型的参数中
    4. //名字与前端的 file的name相同
    5. public String testLoad2(@RequestBody(name="cords") MultipartFile[] cords ,User user,HttpServletRequest request,HttpServletResponse response) throws Exception {
    6. for(MultipartFile cord:cords){
    7. String fileName =cord.getOriginalFilename();
    8. String newFileName=UUID.randomUUID().toString();
    9. newFileName=newFileName+fileName.substring(fileName.lastIndexOf("."),fileName.length());
    10. String path=request.getRealPath("/");
    11. path=path+"upload/";
    12. File filePath=new File(path);
    13. //如果不存在就进行创建
    14. if(!filePath.exists()) {
    15. filePath.mkdir();
    16. }
    17. //写入
    18. cord.transferTo(new File(path+newFileName));
    19. }
    20. return "success";
    21. }

    二、视图解析器

    可以通过配置的形式手动的修改视图解析器,默认采用jstl的视图解析器,springboot可以通过配置使用thymealf   

    要求:jsp全部放在web-inf中

     

    1. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    2. <property name="prefix" value="/WEB-INF/">property>
    3. <property name="suffix" value=".jsp">property>
    4. bean>

    三、拦截器(拦截不了jsp页面)

    拦截器(Interceptor),主要完成请求参数的解析、将页面表单参数赋值给值栈中响应的属性、执行功能检验、程序异常调试等工作

    1 应用场景

       1.权限设置(filter)

       2.性能监控(监控请求的执行时间和响应时间)

    2 过滤器和拦截器的区别

    1. 过滤器是基于函数回调的,而拦截器基于java反射
    2. 过滤器可以过滤所有,拦截器只能拦截请求
    3. 过滤器在请求的声明周期中只能执行一次,而拦截器可以多次执行
    4. 过滤器依赖于servlet容器,而拦截器不依赖于servlet容器
    5. 过滤器无法获取请求值栈中的信息,拦截器可以获取(ModelAndView)

    其实不管是拦截器还是过滤器没什么大的区别,在条件允许的情况下,使用两者那个都可以

    但是能使用拦截器的,不一定能使用过滤器(例如没有servlet容器的情况下,或者是计算响应时间等) 

    3步骤

      3.1定义拦截器   实现HandlerInterceptor接口

    1. package com.sofwin.interceptor;
    2. import javax.servlet.http.HttpServletRequest;
    3. import javax.servlet.http.HttpServletResponse;
    4. import org.springframework.web.servlet.HandlerInterceptor;
    5. import org.springframework.web.servlet.ModelAndView;
    6. //拦截器
    7. public class UserInterceptor implements HandlerInterceptor {
    8. /**
    9. * 请求进入handler以前执行
    10. * 返回true 放行
    11. * 返回false 拦截请求 需要手动去处理
    12. * 参数1 request
    13. * 参数2 response
    14. * 参数3 handler 当前handler
    15. */
    16. @Override
    17. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    18. throws Exception {
    19. System.out.println("pre==========="+handler.getClass().getName());
    20. return true;
    21. }
    22. /**
    23. * 即 方法执行完毕后--在执行这个方法
    24. * @param request
    25. * @param response
    26. * @param handler
    27. * @param modelAndView
    28. */
    29. @Override
    30. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) {
    31. System.out.println("postHandler。。。。。。。。"+modelAndView.getViewName());
    32. }
    33. /**
    34. * 响应完毕后执行这个方法
    35. */
    36. @Override
    37. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    38. throws Exception {
    39. System.out.println("afterComletion======");
    40. }
    41. }

    3.2将拦截器交给spring管理

    1. <bean id="userInterceptor" class="com.sofwin.interceptor.UserInterceptor">bean>

    3.3 配置拦截器

    1. <mvc:interceptors>
    2. <mvc:interceptor>
    3. <mvc:mapping path="/**"/>
    4. <mvc:exclude-mapping path="/a44"/>
    5. <ref bean="userInterceptor"/>
    6. mvc:interceptor>
    7. mvc:interceptors>

     4 拦截器链

      同一个请求被多个拦截器同时拦截,形参拦截器链。

      拦截器链的执行顺序是按照 mvc:interceptors中子标签的声明顺序来确定的

    5 拦截器能拦截什么,不能拦截什么?

    拦截器是拦截不了jsp的页面的

    拦截器只拦截@Controller注解的方法和类,对jsp没有拦截,另外需要注意的是,拦截器是会拦截静态资源的  比如html js css image 这类  ,虽然都是页面但是jsp不需要静态资源

    6 拦截jsp的解决方案: 

       1.将所有的jsp文件放入到WEB-INF文件夹下,这样用户就不能字节访问WEB-INF下的jsp文件了。springmvc的理念是通过Controller例的@RequestMapping来请求相关的jsp页面。

    也就是说,jsp页面的访问需要通过controller来进行一次请求,因为会拦截对controller的请求,所以相当于拦截了jsp页面。 

    如果要做登录的验证,只需要将登录的页面和验证码的页面不拦截,其余页面拦截进行是否登录的验证即可。

    2.另一种就是直接使用过滤器进行登录的验证  ---这里我们推荐使用过滤器的验证 

    使用filter会出现一个问题  过滤后也将静态资源也过滤的

    我们是这样进行过滤的

    1. package com.sofwin.filter;
    2. import java.io.IOException;
    3. import javax.servlet.Filter;
    4. import javax.servlet.FilterChain;
    5. import javax.servlet.FilterConfig;
    6. import javax.servlet.ServletException;
    7. import javax.servlet.ServletRequest;
    8. import javax.servlet.ServletResponse;
    9. import javax.servlet.annotation.WebFilter;
    10. import javax.servlet.http.HttpServletRequest;
    11. import javax.servlet.http.HttpServletResponse;
    12. import javax.servlet.http.HttpSession;
    13. /**
    14. * 用于过滤用户请求,未登录的请求不允许访问除登录外的其他视图
    15. * @author dell
    16. *
    17. */
    18. @WebFilter(urlPatterns = "/*")
    19. public class LoginFilter implements Filter{
    20. @Override
    21. public void destroy() {
    22. }
    23. @Override
    24. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    25. //判断是否为静态资源 如果为静态资源,放行
    26. HttpServletRequest req=(HttpServletRequest)request;
    27. /* uri和url的区别
    28. * 输入的url地址为http://localhost:8080/testproject/test?32fr
    29. * uri为/testproject/test?32fr 是一个String
    30. * url为http://localhost:8080/testproject/test?32fr 是一个StringBuffer
    31. * */
    32. String uri = req.getRequestURI();
    33. //登录成功 session 放入 currentUser
    34. HttpSession session = req.getSession();
    35. Object user = session.getAttribute("currentUser");
    36. //静态资源的放行处理 indexOf(String str) ---> 返回指定子字符串(str)在此字符串(uri)中第一次出现处的索引。 如果此字符串中没有这样的字符出现,则返回 -1
    37. // js是先判断是否有.
    38. if(uri.indexOf("css")>-1||uri.indexOf("images")>-1||(uri.lastIndexOf(".")>-1)&&("js".equals(uri.substring(uri.lastIndexOf("."),uri.length())))) {
    39. chain.doFilter(request, response);
    40. }//登录页面 //验证码
    41. else if(uri.indexOf("login.jsp")>-1) {
    42. chain.doFilter(request, response);
    43. }//登录请求
    44. else if(uri.indexOf("LoginServlet")>-1) {
    45. chain.doFilter(request, response);
    46. }else if(user!=null) {
    47. //登录过 进行放行
    48. chain.doFilter(request, response);
    49. }else {
    50. //过滤请求
    51. //响应登录页面 让用户进行登录 ---使用重定向 放在一直是别的界一直进行过滤
    52. HttpServletResponse resp=(HttpServletResponse)response;
    53. resp.sendRedirect(req.getContextPath()+"/login.jsp");
    54. }
    55. }
    56. @Override
    57. public void init(FilterConfig filterConfig) throws ServletException {
    58. }
    59. }

    7.不拦截静态资源(推荐使用)

    如果前端控制器设置了静态资源进入,但是使用拦截器不设置,拦截器依旧会对静态资源进行拦截

    因此我们设置如下进行静态资源的放行

     

     

     

     

     

     

     

     

     

     

     

     

    8 应用场景的例子

      1.权限设置(拦截器版本) 

     servlet 控制层

    1. //访问 登录界面
    2. @GetMapping("login")
    3. public String testlogin() {
    4. return "login";
    5. }
    6. //进行检查
    7. @GetMapping("checklogin")
    8. public String testlogin1(String userName,String password,HttpServletRequest request) {
    9. if("zhangsan".equals(userName)&&"123".equals(password)) {
    10. request.getSession().setAttribute("user", "user");
    11. return "user/list";
    12. }
    13. return "login";
    14. }

    登录页面 

    1. <%@ page language="java" contentType="text/html; charset=UTF-8"
    2. pageEncoding="UTF-8"%>
    3. html>
    4. <html>
    5. <head>
    6. <link rel="stylesheet" href="css/css1.css">
    7. <meta charset="UTF-8">
    8. <title>Insert title heretitle>
    9. head>
    10. <body>
    11. <form action="checklogin" method="get">
    12. 账号 <input type="text" name="userName" /><br/>
    13. 密码 <input type="text" name="password" /><br/>
    14. <input type="submit" value="登录"/>
    15. form>
    16. body>
    17. html>

     登录成功页面

    1. <%@ page language="java" contentType="text/html; charset=UTF-8"
    2. pageEncoding="UTF-8"%>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>Insert title heretitle>
    8. head>
    9. <body>
    10. 登录成功
    11. body>
    12. html>

    配置文件 

    1. <bean id="userInterceptor" class="com.sofwin.interceptor.UserInterceptor">bean>
    2. <bean id="minorInterceptor" class="com.sofwin.interceptor.MinorInterceptor">bean>
    3. <mvc:interceptors>
    4. <mvc:interceptor>
    5. <mvc:mapping path="/**"/>
    6. <mvc:exclude-mapping path="/login"/>
    7. <mvc:exclude-mapping path="/checklogin"/>
    8. <mvc:exclude-mapping path="/**/*.css"/>
    9. <mvc:exclude-mapping path="/**/*.js"/>
    10. <ref bean="userInterceptor"/>
    11. mvc:interceptor>
    12. mvc:interceptors>

     2.性能监控(监控请求的执行时间和响应时间)

    1. package com.sofwin.interceptor;
    2. import javax.servlet.http.HttpServletRequest;
    3. import javax.servlet.http.HttpServletResponse;
    4. import org.springframework.web.servlet.HandlerInterceptor;
    5. import org.springframework.web.servlet.ModelAndView;
    6. //对请求时间和响应时间进行监视的方法
    7. public class MinorInterceptor implements HandlerInterceptor {
    8. private Long requestTime=0L; //请求时间
    9. private Long responseTime=0L; //响应时间
    10. private Long beginTime=0L; //开始时间
    11. @Override
    12. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    13. throws Exception {
    14. responseTime=System.currentTimeMillis()-beginTime;
    15. System.out.println(request.getRequestURI()+"的响应时间为:"+responseTime);
    16. HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    17. }
    18. @Override
    19. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    20. ModelAndView modelAndView) throws Exception {
    21. requestTime=System.currentTimeMillis()-beginTime;
    22. System.out.println(request.getRequestURI()+"的请求时间为:"+requestTime);
    23. beginTime=System.currentTimeMillis();
    24. }
    25. @Override
    26. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    27. throws Exception {
    28. System.out.println("pre -------");
    29. beginTime =System.currentTimeMillis();
    30. return true;
    31. }
    32. }
    1. <bean id="userInterceptor" class="com.sofwin.interceptor.UserInterceptor">bean>
    2. <bean id="minorInterceptor" class="com.sofwin.interceptor.MinorInterceptor">bean>
    3. <mvc:interceptors>
    4. <mvc:interceptor>
    5. <mvc:mapping path="/**"/>
    6. <ref bean="minorInterceptor"/>
    7. mvc:interceptor>
    8. mvc:interceptors>

    四、全局异常处理器

    用来进行统一的异常处理===jsp中exception对象

    当项目在运行过程中发生异常,会自动被定义的全局异常处理器接收,处理并响应对应的异常页面

    注意:全局异常处理器只能处理服务器的异常。  客户端的异常处理不了

    1.步骤 

       1.1 创建类 实现HandlerExceptionResolver接口

    1. package com.sofwin.exception;
    2. import javax.servlet.http.HttpServletRequest;
    3. import javax.servlet.http.HttpServletResponse;
    4. import org.springframework.stereotype.Component;
    5. import org.springframework.web.servlet.HandlerExceptionResolver;
    6. import org.springframework.web.servlet.ModelAndView;
    7. @Component
    8. //全局异常处理器 ---所有的异常全部抛出 由全局异常处理器来进行处理
    9. public class ExceptionHandler implements HandlerExceptionResolver{
    10. @Override
    11. public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
    12. Exception ex) {
    13. //因为有视图解析器 所以我们不用加jsp等
    14. ModelAndView modelAndView =new ModelAndView("exception");
    15. if(ex instanceof SofwinException) {
    16. SofwinException sf=(SofwinException)ex;
    17. modelAndView.addObject("msg",sf.getMsg());
    18. modelAndView.addObject("cord",sf.getCord());
    19. }
    20. else {
    21. modelAndView.addObject("msg","对不起,网络问题,请稍后访问");
    22. modelAndView.addObject("cord","2222");
    23. }
    24. return modelAndView;
    25. }
    26. }

    2.2 将类交给spring管理

    2.3 自定义异常

    1. package com.sofwin.exception;
    2. public class SofwinException extends Exception {
    3. private String msg;
    4. private String cord;
    5. public String getMsg() {
    6. return msg;
    7. }
    8. public void setMsg(String msg) {
    9. this.msg = msg;
    10. }
    11. public String getCord() {
    12. return cord;
    13. }
    14. public void setCord(String cord) {
    15. this.cord = cord;
    16. }
    17. public SofwinException(String msg, String cord) {
    18. this.msg = msg;
    19. this.cord = cord;
    20. }
    21. public SofwinException() {
    22. super();
    23. }
    24. }

    2.4 方法中抛出异常

    1. @ResponseBody
    2. @GetMapping("ttt")
    3. public String test66(Integer a, Integer b ) throws SofwinException {
    4. if(b==0) {
    5. throw new SofwinException("空指针", "111");
    6. }
    7. float res=a/b;
    8. System.out.println("视图解析器");
    9. return "www";
    10. }

    在可以预知的地方主动抛出异常

    在不可预知的地方设置通用的提示

  • 相关阅读:
    开发过程中的八种确认方法
    《数据仓库入门实践》
    DO280管理和监控OpenShift平台--资源限制
    【HCIE】04.网络安全技术
    leetcode每天5题-Day01
    关于序列化协议,你需要知道的一些内容(2)
    TMS VCL UI包功能和特点
    8.Java数组
    【Kotlin精简】第5章 简析DSL
    物种基因组大小查询之流式结果查询
  • 原文地址:https://blog.csdn.net/weixin_52574640/article/details/125897529