zoukankan      html  css  js  c++  java
  • springmvc

    一、什么是spring MVC

      spring MVC是一个基于MVC模式的一个轻量级web框架,它本身就是spring框架的一个模块,所以可以和spring框架无缝结合。其可以简化web开发,是一个比struts2更加方便的MVC框架。

    二、springMVC的执行流程  

      1.DispatcherServlet :前端控制器,DispatcherServlet拦截请求对URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping;

      2.HandlerMapping : 处理器映射,DispatcherServlet调用该处理映射器,获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回给DispatcherServlet ;

      3.HandlerAdapter :处理器适配器,DispatcherServlet或得了Handler对象之后,就会调用对应的HandlerAdapter来对请求进行处理(执行对应的拦截器和Handler),并返回ModelAndView给DispatcherServlet。

      4.Handler :处理器,HandlerAdapter执行Handler的方法并返回ModelAndView给HandlerAdapter。

      5.ViewResolver:视图解析器,DispatcherServlet得到了ModelAndView后,调用ViewResolver来解析得到view(真正的视图对象)。

      6.DispatcherServlet 有了view之后,就可以利用Model中的数据对视图进行渲染,并响应用户的请求。

      流程图大致如下:

         

    三、springMVC的使用

      1.引入jar包,引入springMVC相关jar包,文件上传jar包,json转换相关jar包

        

      2.在web.xml中配置springMVC核心过滤器

      <!-- 配置spring MVC核心过滤器 -->
      <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!-- 该配置文件默认是WEB-INF目录下上面的servlet-name-servlet.xml,如:dispatcherServlet-servlet.xml -->
            <param-value>classpath*:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
      
      <!-- 解决中文乱码问题(无法解决get请求的乱码问题) -->
      <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
      
      <!-- contextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息 -->
      <!-- 如果只用springMVC这个配置可以不要 -->
      <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      <context-param>  
      <param-name>contextConfigLocation</param-name>  
         <param-value>classpath:applicationContext.xml</param-value>  
      </context-param> 

       3.总共有三种方式来创建处理器Handler,

        ①实现Controller接口,并实现其handleRequest方法,这种方式一个实现类中只有一个方法会被请求到。

          ②继承MultiActionController类,自己新建方法来进行映射,这种方式一个类中可以有多个方法来响应请求。

        ③用注解的方式声明,@Controller或@RestController

        

    public class HelloWorldController implements Controller {
    
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            
            System.out.println("传入的数据为");
            String userName=request.getParameter("userName");
            System.out.println("userName:"+userName);
            
            //封装数据,可以直接使用request对象,也可以使用封装等方式,真正使用时可以选择一种
            request.setAttribute("rUserName", userName);
            Map<String, String > map=new HashMap<String, String>();
            map.put("mUserName",userName);
            
            //返回视图层,如果使用map封装数据,需要作为(第二个)参数传递,也是request作用域。
            return new ModelAndView("forward:/index.jsp",map);
        }
    }
    
    
    public class HelloSpringMvcController extends MultiActionController {
    
        public ModelAndView add(HttpServletRequest request,HttpServletResponse response){
            String userName=request.getParameter("userName");
            System.out.println("传入的数据为userName:"+userName);
            
            //封装数据,可以直接使用request对象,也可以使用封装等方式,真正使用时可以选择一种
            request.setAttribute("rUserName", userName);
            Map<String, String > map=new HashMap<String, String>();
            map.put("mUserName",userName);
            
            //返回视图层,如果使用map封装数据,需要作为(第二个)参数传递,也是request作用域。
            return new ModelAndView("/index.jsp",map);
        }
        
        public ModelAndView update(HttpServletRequest request,HttpServletResponse response){
            String userName=request.getParameter("userName");
            System.out.println("传入的数据为userName:"+userName);
            
            //封装数据,可以直接使用request对象,也可以使用封装等方式,真正使用时可以选择一种
            request.setAttribute("rUserName", userName);
            return new ModelAndView("/index.jsp");
        }
    }
    
    @Controller
    @RequestMapping("/annotion")
    public class AnnotionController{
    
        /**
         * 下面5个参数是springMVC默认支持的参数类型,我们只需在方法上给出这些参数就能够使用
         * HttpServletRequest request
         * HttpServletResponse response
         * HttpSession session
         * Model modelModel
         * Map modelMap
         */
        @RequestMapping("/get")
        public ModelAndView get(HttpServletRequest request,HttpServletResponse response,
                HttpSession session,Model model,ModelMap modelMap){
            
            String userName=request.getParameter("userName");
            request.setAttribute("request", "request:"+userName);
            session.setAttribute("session", "session:"+userName);
            model.addAttribute("model", "model:"+userName);
            ModelAndView modelAndView = new ModelAndView("/index2.jsp");
            modelAndView.addObject("modelAndView", "modelAndView:"+userName);
            
            return modelAndView;
        }
    }

      4.springmvc.xm配置文件

        ①通过BeanNameUrlHandlerMapping来映射请求和处理器之间对应的关系,通过name来进行匹配    

      <bean id="helloweb" class="test.controller.HelloWebController"></bean>
        
        <!-- 使用BeanNameUrlHandlerMapping来对处理器进行映射,这种映射关系,一个请求就对应着一个Controller类 -->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
        <!-- 声明bean的name,因为使用了BeanNameUrlHandlerMapping,其实bean的id和name也可以当作name,也可以使用id,但是推荐使用name-->
        <bean name="/helloworld" class="test.controller.HelloWorldController"></bean>

        ②通过SimpleUrlHandlerMapping来映射   

       <!-- 使用BeanNameUrlHandlerMapping来对处理器进行映射,这种映射关系,一个请求就对应着一个Controller类 -->
        <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
            <!-- 配置URL与ACTION对象ID进行映射 ,<prop key="second.action">second</prop>,其中key匹配url信息,value为controller的ID -->
                <props>
                    <prop key="helloweb">helloweb</prop>
                    <prop key="hellojava">hellojava</prop>
                </props>
            </property>
        </bean>

        ③和上面方式结合,在一个处理器内部映射多个方法对请求进行处理

    <!-- 使用BeanNameUrlHandlerMapping来对处理器进行映射,这种映射关系,一个请求就对应着一个Controller类 -->
        <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
            <!-- 配置URL与ACTION对象ID进行映射 ,<prop key="second.action">second</prop>,其中key匹配url信息,value为action的ID -->
                <props>
                    <prop key="helloweb">helloweb</prop>
                    <prop key="hellojava">hellojava</prop>
                    <prop key="hellospringmvc">hellospringmvc</prop>
                </props>
            </property>
        </bean>
        
        <bean id="hellospringmvc" class="test.controller.HelloSpringMvcController" >
            <property name="methodNameResolver" ref="parameterMethodNameResolver"></property>
        </bean>
        <!-- 定义通过方法名调用控制器相关方法的规则 -->
        <bean id="parameterMethodNameResolver"
                class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
            <!-- 在url中使用do=方法名方式识别相关方法,例如:studentMulti.action?do=add,将调用add方法;这里的do不是固定的,可以改为其它 -->
            <property name="paramName" value="do" />
            <!-- 如果没有指定方法名时,默认 调用控制器的list方法 -->
            <property name="defaultMethodName" value="list" />
        </bean>

        ④对返回的视图加上前缀和后缀

      <!-- 支持servlet与jsp视图解析,可进行进一步处理,此步可省略 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 可以加前缀或后缀 -->
            <!-- <property name="prefix" value="/jsp/"/>
            <property name="suffix" value=".jsp"/>  --> 
        </bean>

        ⑤使用注解扫描,这样就能用注解替代上面繁琐的配置,简化开发

      <!-- 开启注解扫描 -->
        <mvc:annotation-driven/>
        <context:component-scan base-package="test">
           <!-- 可以设置扫描哪些包或者注解 -->
           <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> -->
        </context:component-scan>

      5.springMVC的拦截器   

    public class MyInterceptor1 implements HandlerInterceptor {
    
        /**
         * 访问请求资源前执行,返回true则继续执行,返回false则不执行。
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("MyInterceptor1:preHandle");
            return true;
        }
    
        /**
         * 访问请求资源后(但在渲染视图之前),如果没有异常,将执行此方法
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            System.out.println("MyInterceptor1:postHandle");
        }
    
        /**
         * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,不管理有没有异常都一定执行此方法
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            System.out.println("MyInterceptor1:afterCompletion");
        }
    
    }
    public class MyInterceptor2 implements HandlerInterceptor {
    
        /**
         * 访问请求资源前执行,返回true则继续执行,返回false则不执行。
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println("MyInterceptor2:preHandle");
            return true;
        }
    
        /**
         * 访问请求资源后(但在渲染视图之前),如果没有异常,将执行此方法
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            System.out.println("MyInterceptor2:postHandle");
        }
    
        /**
         * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,不管理有没有异常都一定执行此方法
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            System.out.println("MyInterceptor2:afterCompletion");
        }
    
    }
    <!-- 拦截器 -->
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/annotion/get"/>
                <bean class="test.Interceptor.MyInterceptor1"></bean>
            </mvc:interceptor>
            <mvc:interceptor>
                <mvc:mapping path="/annotion/get"/>
                <bean class="test.Interceptor.MyInterceptor2"></bean>
            </mvc:interceptor>
        </mvc:interceptors>

      6.springMVC异常处理

        ①实现HandlerExceptionResolver接口对异常进行处理,并将该实现类交给容器进行管理

    public enum StatusCode {
        
        id_not_null(100001,"id不能为空"),
        
        success(0, "操作成功") ,
        error(9999, "服务器异常");
        
        private int status;
        private String info;
        
        private StatusCode(int status, String info) {
            this.status = status;
            this.info = info;
        }
    
        public int getStatus() {
            return status;
        }
        public void setStatus(int status) {
            this.status = status;
        }
    
        public String getInfo() {
            return info;
        }
        public void setInfo(String info) {
            this.info = info;
        }
        
    }
    public class ServiceException extends Exception {
    
        private static final long serialVersionUID = 1L;
        
        private int code;
        private String name;
        
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public ServiceException(){}
        
        public ServiceException(int code,String name){
            this.code = code;
            this.name = name;
        }
    
    }
    @Component
    public class ServiceExceptionResolver implements HandlerExceptionResolver {
    
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception ex) {
            ServiceException serviceException = null;
            if(ex instanceof ServiceException){
                serviceException = (ServiceException)ex;
            }else{
                serviceException = new ServiceException(StatusCode.error.getStatus(),StatusCode.error.getInfo());
                ex.printStackTrace();
            }
            
            ModelAndView mv = new ModelAndView(); 
            response.setStatus(HttpStatus.OK.value()); //设置状态码  
            response.setContentType(MediaType.APPLICATION_JSON_VALUE); //设置ContentType  
            response.setCharacterEncoding("UTF-8"); //避免乱码  
            response.setHeader("Cache-Control", "no-cache, must-revalidate");  
            try {
                response.getWriter().write("{"success":false,"code":""+serviceException.getCode()+"","msg":"" + serviceException.getName() + ""}");
            } catch (IOException e) {
                e.printStackTrace();
            }  
    
            return mv;  
        }
    
    }

        ②使用@ControllerAdvice和@ExceptionHandler来对异常进行统一处理

    @ControllerAdvice
    public class BaseController {
    
        /** 基于@ExceptionHandler异常处理 */
        @ResponseBody
        @ExceptionHandler
        public Map<String, Object>  handleAndReturnData(HttpServletRequest request, HttpServletResponse response, Exception ex) {
    
            Map<String, Object> data = new HashMap<String, Object>();
            ServiceException e = null;
            if(ex instanceof ServiceException) {
                e = (ServiceException)ex;
            }else{
                e = new ServiceException(StatusCode.error.getStatus(),StatusCode.error.getInfo());
            }
            data.put("code", e.getCode());
            data.put("msg", e.getName());
            data.put("success", false);
            return data;
        }
    }

        ③定义一个父类,并用@ExceptionHandler来标注一个方法来对异常进行处理

    public class BaseController {
    
        /** 基于@ExceptionHandler异常处理 */
        @ResponseBody
        @ExceptionHandler
        public Map<String, Object>  handleAndReturnData(HttpServletRequest request, HttpServletResponse response, Exception ex) {
    
            Map<String, Object> data = new HashMap<String, Object>();
            ServiceException e = null;
            if(ex instanceof ServiceException) {
                e = (ServiceException)ex;
            }else{
                e = new ServiceException(StatusCode.error.getStatus(),StatusCode.error.getInfo());
            }
            data.put("code", e.getCode());
            data.put("msg", e.getName());
            data.put("success", false);
            return data;
        }
    }
    @RequestMapping("/exception")
    public class ExceptionController extends BaseController{
    
        @RequestMapping("/info")
        public User info(User user) throws ServiceException{
            throw new ServiceException(StatusCode.id_not_null.getStatus(),StatusCode.id_not_null.getInfo());
        }
    }

      

      7.文件上传下载

      

    @Controller
    @RequestMapping("file")
    public class FileUDController {
    
        @ResponseBody
        @RequestMapping("/upload")
        public String upload(HttpServletRequest request,
                @RequestParam("files") MultipartFile[] files) throws Exception {
    
            String path = "C:/file";
            for(MultipartFile file : files){
                //如果文件不为空,写入上传路径
                if(!file.isEmpty()) {
                    //上传文件路径
                    //上传文件名
                    String filename = file.getOriginalFilename();
                    File filepath = new File(path,filename);
                    //判断路径是否存在,如果不存在就创建一个
                    if (!filepath.getParentFile().exists()) { 
                        filepath.getParentFile().mkdirs();
                    }
                    //将上传文件保存到一个目标文件当中
                    file.transferTo(new File(path + File.separator + filename));
                }
            }
            return "success";
            
        }
        
        @ResponseBody
        @RequestMapping("/download")
        public String download(HttpServletRequest request,HttpServletResponse response,
                @RequestParam("fileName") String fileName) throws Exception {
    
            //下载文件路径,使用nio方式
            Path path = Paths.get("C:/file" + File.separator + fileName);
            response.setHeader("Content-Disposition", "attachment; filename="" + URLEncoder.encode(fileName, "UTF-8") + """);  
            response.setContentType("application/octet-stream;charset=UTF-8");  
            OutputStream outputStream = response.getOutputStream();  
            Files.copy(path, response.getOutputStream());
            outputStream.flush();  
            outputStream.close(); 
            return "success";
        }
        
        
        @RequestMapping("download2")    
        public ResponseEntity<byte[]> download(@RequestParam("fileName") String fileName) throws IOException {
            String path = "C:/file";
            File file = new File(path + File.separator + fileName);  
            HttpHeaders headers = new HttpHeaders();
            //使用URLEncoder.encode是为了解决get请求文件名乱码的问题
            headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, "UTF-8"));   
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);   
            return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),    
                                              headers, HttpStatus.CREATED);    
        }    
    }
    <!-- 文件上传 -->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <!-- 上传文件大小上限,单位为字节(10MB) -->
            <property name="maxUploadSize">  
                <value>10485760</value>  
            </property>  
            <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
            <property name="defaultEncoding">
                <value>UTF-8</value>
            </property>
        </bean> 
      
  • 相关阅读:
    Android Studio中的Java控制台中出现乱码问题?
    博客第二天——头插法建立单链表
    博客志第一天——判断一个整数N是否是完全平方数?
    绝对定位篇
    JavaScript 事件循环
    var与let变量for遍历的问题
    获取url中参数值
    Js不用for,forEach,map等循环实现九九乘法表
    前端常见浏览器兼容性问题
    js常见面试题
  • 原文地址:https://www.cnblogs.com/kyleinjava/p/9106302.html
Copyright © 2011-2022 走看看