美文网首页
Springmvc框架

Springmvc框架

作者: 小月半会飞 | 来源:发表于2018-11-26 12:59 被阅读0次

    1、原理

    1. 客户端请求提交到DispatcherServlet
    2. 由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller
    3. DispatcherServlet将请求提交到Controller
    4. Controller调用业务逻辑处理后,返回ModelAndView
    5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
    6. 视图负责将结果显示到客户端

    2、环境搭建

    1)、添加jar包依赖:

    在项目的WEB-INF下新建一个lib文件夹,将以下jar包添加进去,并且add as libraries:
    spring-aop-4.0.4.RELEASE.jar

    spring-beans-4.0.4.RELEASE.jar

    spring-context-4.0.4.RELEASE.jar

    spring-core-4.0.4.RELEASE.jar

    spring-expression-4.0.4.RELEASE.jar

    spring-web-4.0.4.RELEASE.jar

    spring-webmvc-4.0.4.RELEASE.jar

    commons-logging-1.1.1.jar(用来打印log)

    2)、添加资源目录

    在项目下新建一个文件夹config,转成资源目录,创建文件springmvc.xml文件,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
     <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:mvc="http://www.springframework.org/schema/mvc"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
             http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
             <!-- 配置自动扫描的包 -->
             <context:component-scan base-package="com.neusoft.controller"></context:component-scan>
             <!-- 配置视图解析器 如何把handler 方法返回值解析为实际的物理视图 -->
             <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                  <--   给所有return “”里面的内容添加前缀和后缀   -->
                 <property name = "prefix" value="/WEB-INF/views/"></property>
                 <property name = "suffix" value = ".jsp"></property>
             </bean>
     </beans>
    
    

    3)、配置web.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
    id="WebApp_ID" version="3.1">
      
        <!-- 配置DispatchcerServlet -->
        <servlet>
            <servlet-name>springDispatcherServlet</servlet-name>
             <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
             <!-- 配置Spring mvc下的配置文件的位置和名称 -->
             <init-param>
                 <param-name>contextConfigLocation</param-name>
                 <param-value>classpath:springmvc.xml</param-value>
             </init-param>
             <load-on-startup>1</load-on-startup>
         </servlet>
         <servlet-mapping>
             <servlet-name>springDispatcherServlet</servlet-name>
        <!-- 这里的servlet-mapping表示拦截的模式,这里是“*.do”,表示对于.do结尾的请求进行拦截 -->
             <url-pattern>*.do</url-pattern>
         </servlet-mapping>
    </web-app>
    

    理解:
    根据网页上发送过来的请求,去实例化springDispatcherServlet类,然后根据init-param里面的param-value的值去找到自动化配置的包,然后在找到XX.do方法,完成相应的操作

    4)通过上述方法进入hello.jsp

    1、先创建一个com.neusoft.controller包
    2、在包下创建一个HelloController类
    3、在类的前面添加“@Controller”注解,表示是spring的控制器
    4、在方法前面添加对应的@RequestMapping("hello.do"),用于匹配路径;

    代码实现:

    @Controller
    public class HelloController {
        @RequestMapping("hello.do")
        public String hello(){
            System.out.println("hello");
            return "hello";
        }
    }
    

    使用:启动tomcat服务器,在网页上请求"localhost:8080/hello.do",通过mvc框架匹配到hello方法,然后通过return返回值里面的内容,进入WEB-INF/jsp/hello.jsp

    3、Controller方法的返回值

    1)、ModelAndView

    ModelAndView中的Model代表模型,View代表视图。

    业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该Spring MVC框架。

    框架通过调用配置文件中定义的视图解析器,对该对象进行解析,最后把结果数据显示在指定的页面上。

    代码实现:

    @Controller
    public class HelloController {
        @RequestMapping("hello.do")
        public ModelAndView hello(){
            System.out.println("hello");
            ModelAndView modelAndView=new ModelAndView();
    //      在View属性中设置要跳转的view
            modelAndView.setViewName("hello");
    //      存储值到Model出行中
            modelAndView.addObject("username","zhangsan");
            return modelAndView;
        }
    }
    

    2)、String

    String可以有三种类型:

    1、普通字符串:表示视图的名,由于前面配置了同意的前缀后缀,所以此处的字符串真实值是:“前缀”+视图名+“后缀”;
    @Controller
    public class HelloController {
        @RequestMapping("world.do")
        public String world(Model model) {
            System.out.println("world");
    //      往model属性中传值
            model.addAttribute("username","lisi");
    //      返回到WEB-INF/jsp/world.jsp中,带着model属性值
            return "world";
    //        错误跳转,404
    //      return "world2.do";
    }
        @RequestMapping("world2.do")
        public String world2(){
    //      返回到WEB-INF/jsp/world.jsp中
            return "world";
        }
    }
    
    2、redirect重定向:redirect的特点和servlet一样,对比response.serndRedirect(""),使用redirect进行重定向那么地址栏中的URL会发生变化,不传request值,走doGet请求,相对较慢,因为实际上是两次跳转,也叫外部跳转
    @Controller
    public class HelloController {
        @RequestMapping("world.do")
        public String world(HttpServletResponse response) {
            System.out.println("world");
    //        通过response自带的方法重定向,使用此方法最好将String累心该方法改成void;
    //        response.sendRedirect("world2.do");
    //       重定向,只能往XX.do方法跳,因为写在WEB-INF下的jsp不能通过网页访问直接进去,如果要传值也不能再用request了,要使用session
            return  "redirect:world2.do";
        }
        @RequestMapping("world2.do")
        public String world2(){
            return "world";
        }
    }
    
    3、forward转发:对比servlet中的request.sendDisparchar("路径").forward(request,response),地址栏中的URL不会发生改变,能传request值,不能跳站外,相对要快,因为是一次跳转,也称内部跳转
    @Controller
    public class HelloController {
        @RequestMapping("world.do")
        public String world(Model model) {
            System.out.println("world");
    //        往request作用域存值
            request.setAttribute("username","wangwu");
    //        内部跳转:内部跳转时不再自动加前缀后缀,需要自动补全
    //        return "forward:WEB-INF/jsp/world.jsp";
    //        内部跳转:往其他方法里面跳
            return "forward:world2.do";
    //        以上两种跳转均带request作用域值
        }
        @RequestMapping("world2.do")
        public String world2(){
            return "world";
        }
    }
    

    2)、void

    可以使用Controller方法的HTTPServletRequest和HTTPServletResponse对象进行请求的接收和响应

    1)使用request转发页面:
    request.getRequestDispatcher("转发路径").forward(request,response);
    2)使用response进行页面重定向
    response.sendRedirect("重定向路径");
    3)也可以使用response指定响应结果:
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json;charset=utf-8");
    response.getWriter().println("json串");
    代码实现:

    @Controller
    public class LoginController {
        @RequestMapping("login.do")
        public void login(HttpServletResponse response) throws IOException {
            System.out.println("login");
            response.setContentType("text/html;charset=utf-8");
    //        往页面写内容
            response.getWriter().println("Login!");
            response.getWriter().println("登录!");
        }
    }
    

    4、SpringMVC的各种参数绑定方式

    1)、基本数据类型

    form表单提交

    <form method="post" action="${pageContext.request.contextPath}/hello.do">
        姓名:<input type="text" name="username">
        籍贯:<input type="text" name="city">
        年龄:<input type="text" name="age">
        电话:<input type="text" name="telephone">
        <input type="submit" value="提交">
      </form>
    

    controller部分代码:

    @RequestMapping("count.do")
    public void count(String   username, String  city , Integer age ,String  telephone) {
          System.out.println(username);
          System.out.println(city);
          System.out.println(age);
          System.out.println(telephone);
    }
    

    imput部分的值对应的name与count方法传递的参数变量名保持一致,注意如果表单提交的值是空,如果使用int基本类型去接,就会出现数据转换异常,所以最好使用Integer包装类

    2)、自定义对象类型

    创建一个com.neusoft.dto包,定义一个User类,属性名称与input里面的name对应

    package com.neusoft.dto;
    
    public class User {
        private String username;
        private String city;
        private Integer age;
        private String telephone;
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getTelephone() {
            return telephone;
        }
    
        public void setTelephone(String telephone) {
            this.telephone = telephone;
        }
    }
    

    表单和前面的一样
    controller部分代码:

    @RequestMapping("hello.do")
        public ModelAndView hello(User user){
            System.out.println("hello");
            ModelAndView modelAndView=new ModelAndView();
            modelAndView.setViewName("hello");
            System.out.println(user.getUsername());
            modelAndView.addObject("user",user);
            return modelAndView;
        }
    

    hello.jsp部分代码:

    <h3>大家好,我叫${user.username} ,来自${user.city} ,今年${user.age}岁,电话号码${user.telephone} </h3>
    

    5、解决乱码问题

    上面的扁担提交有可能出现乱码问题,因为传递中文了,下面我们就来解决乱码,在web.xml中添加自带的过滤器,代码如下

    <filter>
    
            <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
    
            <url-pattern>/*</url-pattern>
    
        </filter-mapping>
    

    6、RESTful架构

    主要实现从url传递参数

    1)、修改web.xml,添加DispatcherServlet的Restful配置

    <servlet>
    
            <servlet-name>springmvc-servlet-rest</servlet-name>
    
                   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
                   <init-param>
    
                       <param-name>contextConfigLocation</param-name>
    
                       <param-value>classpath:spring/springmvc.xml</param-value>
    
                   </init-param>
    
               </servlet>
    
               <servlet-mapping>
    
                    <servlet-name>springmvc-servlet-rest</servlet-name>
                   <--  注意这里发生了变化,由之前的*.do变成了/   -->
                   <-- <url-pattern>*.do</url-pattern>-->
                    <url-pattern>/</url-pattern>
    
                </servlet-mapping>
    

    注意这里url-pattern发生了变化,由之前的*.do变成了/,意味着会对所有的请求的路径进行拦截,所以如果再使用/表示路径,比如进入locahost:8080/abc.jsp也会进行拦截,会把abc.jsp当做是一个指令,然后去springmvc中context配置的自动扫描包下面去寻找,没有找到就会直接报404错误,但是这个也有办法解决,这就涉及到后面会写到的静态资源访问。

    2)、jsp部分代码:

    <a href="${pageContext.request.contextPath}/count/3/张三">url参数传递</a>
    

    3)controller部分:

     /*@RequestMapping("count/{id}")
        count后面{}里面内容与方法里面的参数名字不一样时写法
        public String count(@PathVariable("id") Integer num){}*/
        @RequestMapping("count/{num}/{name}")
        public String count(@PathVariable Integer num,@PathVariable String name){
            System.out.println(num);
            System.out.println(name);
            return "world";
        }
    

    7、静态资源访问<mvc:resources>

    前面我们已经将DispatcherServlet中的url-pattern设置为 /,所以如果访问css,js等目录下的内容也会被DispatcherServlet拦截,而我们可以通过在springmvc.xml中配置<mvc:resources>,来使得这些文件跳过拦截

    <mvc:annotation-driven></mvc:annotation-driven>
     <mvc:resources location="/js/" mapping="/js/**"/>
     <mvc:resources location="/css/" mapping="/css/**"/>
    

    由于以后静态文件可能会有很多个,为了不一一配置,所以我建了一个static文件夹,将这些静态文件豆放在一个文件夹下面,这个文件夹最好直接建在web下面,而不是WEB-INF下面,因为WEB-INF是受保护的文件夹,里面的资源不能够被网页直接访问,只能通过内部访问

     <mvc:annotation-driven></mvc:annotation-driven>
        <mvc:resources  mapping="/static/**" location="/static/"/>
    

    我们也可以将我们的index欢迎页面保护起来,使得不能通过浏览器直接访问,首先将index放入WEB-INF/jsp目录下,然后在web.xml中添加配置,代码如下:

    <!--修改起始页面位置-->
        <welcome-file-list>
            <welcome-file>/WEB-INF/jsp/index.jsp</welcome-file>
        </welcome-file-list>
    

    8、文件上传

    首先在springmvc.xml中添加配置,设置文件的mapper

        <!-- 文件上传mapper -->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="80000"></property>
            <property name="defaultEncoding" value="UTF-8"></property>
        </bean>
    

    然后在jsp中写文件上传的代码,文件提交也是用表单提交,但是要添加一个enctype="multipart/form-data"属性,代码如下:

    <%--文件上传表单--%>
      <form method="post" action="${pageContext.request.contextPath}/unload" enctype="multipart/form-data">
        username:<input name="username"  type="text">
        <%--文件上传--%>
        <input type="file" name="pic">
        <input type="submit" value="submit">
      </form>
    

    controller部分代码:

    @Controller
    public class UnloadController {
        @RequestMapping("unload")
        public void unload(String username, @RequestParam MultipartFile pic, HttpServletRequest request) throws IOException {
            System.out.println(username);
            String fileName=pic.getOriginalFilename();
            ModelAndView modelAndView=new ModelAndView();
            if(pic.getSize()>0){
                String realPath=request.getServletContext().getRealPath("/static/img")+File.separator;
                File files=new File(realPath);
                if(!files.exists()){
                    files.mkdirs();
                }
                System.out.println(realPath);
                File file=new File(realPath+fileName);
                pic.transferTo(file);
                System.out.println(fileName);
               //这种形式下,默认会返回unload.jsp  
            }
        }
    }
    

    我们传上来的图片也可以实时的显示在我们的网页上,在某一网页上添加一行代码,这里用index.jsp做示范:

        <%--从图片的存储位置,根据图片名字取出图片--%>
    <img src="${pageContext.request.contextPath}/static/img/${picname}" name="picc">
    

    controller部分的修改:

    @Controller
    public class UnloadController {
        @RequestMapping("unload")
    //返回类型做了修改,指定返回某一页面
        public ModelAndView unload(String username, @RequestParam MultipartFile pic, HttpServletRequest request) throws IOException {
            System.out.println(username);
            String fileName=pic.getOriginalFilename();
            ModelAndView modelAndView=new ModelAndView();
            if(pic.getSize()>0){
                String realPath=request.getServletContext().getRealPath("/static/img")+File.separator;
                File files=new File(realPath);
                if(!files.exists()){
                    files.mkdirs();
                }
                System.out.println(realPath);
                File file=new File(realPath+fileName);
                pic.transferTo(file);
                System.out.println(fileName);
    //          指定返回WEB-INF/jsp/index.jsp页面
                modelAndView.setViewName("index");
    //          传递picname的值,使得当前图片能在跳转后的页面显示出来
                modelAndView.addObject("picname",fileName);
            }
            return modelAndView;
        }
    }
    

    9、拦截器

    可以对指定的方法进行拦截,首先在springmvc.xml中添加配置,代码如下:

    <mvc:interceptors>
    
            <!--如果配置了多个拦截器,则按顺序执行 -->
    
            <!-- 登陆认证拦截器 -->
    
            <mvc:interceptor>
    
                <!-- /**表示所有url包括子url路径 -->
                <!-- 拦截的方法,对所有带/admin/的指令进行拦截,并在对应的class做出处理 -->
                <mvc:mapping path="/admin/**"/>
                <!-- 对应的拦截类,做出处理 -->
                <bean class="com.neusoft.interceptor.FirstInterceptor"></bean>
    
            </mvc:interceptor>
    
        </mvc:interceptors>
    

    拦截器可以有多个,写在前面的先执行,前面的执行完就忘后面的拦截器里面跳
    新建一个com.neusoft.interceptor包,新建一个FirstInterceptor类,实现一个HandlerInterceptor接口

    public class FirstInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
    //        return false;
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    

    对应的controller也需要修改,代码如下:

    @Controller
    @RequestMapping("admin")
    public class HelloController {
        /*@RequestMapping("count/{id}")
        public String count(@PathVariable("id") Integer num){}*/
        @RequestMapping("count/{num}/{name}")
        public String count(@PathVariable Integer num,@PathVariable String name){
            System.out.println(num);
            System.out.println(name);
            return "world";
        }
    }
    

    对应jsp中使用的方法:

    <a href="${pageContext.request.contextPath}/admin/count/3/长大">计数</a>
    

    理解:当服务器发出计数请求,服务器就会识别是否属于拦截器的拦截对象,是就会对这个方法进行拦截,然后在拦截器中的preHandle方法当进行操作,然后再运行controller类当中的方法,之后再运行postHandle,afterCompletion方法,然后结束接着拦截器,返回jsp

    现在补充一个人放到链接:
    首先配置springmvc.xml

    <mvc:interceptors>
    
            <!--如果配置了多个拦截器,则按顺序执行 -->
    
            <!-- 登陆认证拦截器 -->
    
            <mvc:interceptor>
    
                <!-- /**表示所有url包括子url路径 -->
                <!-- 拦截的方法 -->
                <mvc:mapping path="/**"/>
                <!-- 对应的拦截类,做出处理 -->
                <mvc:exclude-mapping path="/gologin/**"></mvc:exclude-mapping>
                <mvc:exclude-mapping path="/login/**"></mvc:exclude-mapping>
                <bean class="com.neusoft.interceptor.FirstInterceptor"></bean>
    
            </mvc:interceptor>
    
        </mvc:interceptors>
    

    jsp部分代码:
    现在index.jsp做一个登录入口:

    <a href="${pageContext.request.contextPath}/gologin">登录</a>
      <h5>你好${username}</h5>
    

    然后写一个登录页面:

    <body>
    <form method="post" action="${pageContext.request.contextPath}/login" >
        username:<input type="text" name="username">
        password:<input type="password" name="password">
        <input type="submit">
    </form>
    

    然后写对应的controller方法:

    @Controller
    public class LoginController {
        @RequestMapping("gologin")
        public String gologin(HttpServletResponse response) throws IOException {
            System.out.println("gologin");
            return "login";
        }
        @RequestMapping("login")
        public String login(String username, String password, HttpServletRequest request){
            System.out.println("login");
            HttpSession session=request.getSession();
            if(username.equals("admin")&&password.equals("123456")){
                session.setAttribute("username",username);
                return "index";
            }
            return "login";
        }
    }
    

    interceptor:

    public class LoginInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
            HttpSession  session=httpServletRequest.getSession();
            if(session.getAttribute("username")!=null){
                return true;
            }else {
                httpServletRequest.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(httpServletRequest,httpServletResponse);
            }
            return false;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    

    然后就能实现拦截器的功能

    相关文章

      网友评论

          本文标题:Springmvc框架

          本文链接:https://www.haomeiwen.com/subject/putbqqtx.html