zoukankan      html  css  js  c++  java
  • Spring MVC 笔记

     
    Spring MVC基本概念:
    1、DispatcherServlet: 前端控制器
    2、Controller: 调用业务逻辑生成model的地方
    3、HandlerAdapter:是被dispatcherServlet使用的,dispatcherServlet通过handlerAdapter来调用controller方法,handler其实是dispatcherServlet内部使用的一个类。
    4、HandlerInterceptor:拦截器 该接口提供after postHandle preHandle 三个方法,调用controller前后使用
    5、HandlerMapping:负责确定DispatcherServelet与controller之间映射的类,告诉DispatcherServelet,在请求到来后,由哪个controller来响应这个请求
    6、HandlerExecutionChain: preHandle->Controller method->postHandle->afterCompletion的执行链
    7、ModelAndView:model的具体表现
    8、viewResolver:视图解析器,决定需要用哪个视图来进行视图的呈现。
    9、view:界面
     
    Spring MVC的原理流程
     
    ModelAndView是springmvc的封装对象,将model和view封装在一起。
     
    一个中心:(不需要开发
    DispatcherServlet前端控制器
    三个组件:不需要开发
     处理器映射器
    处理器适配器
    视图解析器
     
    Handler:(需要开发,上图的第5步,第6步之间的Handler处理器)
    处理器,理解成action
     
    View
    需要开发页面:jsp
     
    springmvc的框架原理
    包括哪些组件:
    前端控制器(中心)
    处理器映射器(三大组件)
    作用:根据url找到Handler.
    处理器适配器(三大组件)
    作用:执行Handler
    视图解析器(三大组件)
    作用:解析出View,根据逻辑视图名解析出真正的视图
     
    开发springmvc程序的步骤
    第一步:配置前端控制器
    在web.xml配置DispathcherServlet前端控制器
    第二步:配置springmvc的全局配置文件
    配置三大组件:
    处理器映射器:
             根据url查找 Handler
    处理器适配器:
             执行Handler
    视图解析器:
             解析出视图View,根据逻辑视图名解析出真正的视图。
     
    第三步:按照处理器适配器规则开发Handler(action
    第四步:将Handler配置在spring容器中。
    第五步:编写视图(jsp+jstl
     
    处理器映射器:
    作用:根据url找到Handler.
    ①形式 BeanNameUrlHandlerMapping
    根据url匹配bean的name 处理器映射器实现了HandlerMapping接口
    <bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
     
    <!-- 配置action -->
    <bean id="hello_controller" name="/helloworld.action" class="cn.itcast.springmvc.Hello" />
     
     
    ②形式 SimpleUrlHandlerMapping
    将url进行集中配置
    实现了HandlerMapping接口,处理url到bean的映射
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
    <props>
    <prop key="/hello1.action">hello_controller</prop>
    <prop key="/hello2.action">hello_controller</prop>
    <prop key="/hello3.action">hello_controller3</prop>
    </props>
    </property>
    </bean>
     
    <!-- 配置action -->
    <bean id="hello_controller" name="/helloworld.action" class="cn.itcast.springmvc.Hello" />
     
    总结:
    多个处理器映射器可以共存
     
    ③注解映射器形式
    <!--注解映射器 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
     
    ④<mvc:annotation-driven />代替注解映射器
     
     
    处理器适配器
    执行Handler
    ①形式 SimpleControllerHandlerAdapter
    SimpleControllerHandlerAdapter:规则是Handler要实现Controller接口
    <bean
    class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
     
    public class Hello implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request,
    HttpServletResponse response) throws Exception {
    ModelAndView modelAndView = new ModelAndView();
    //向页面显示一行提示信息
    //下边的方法就相当于request.setAttribute(arg0, arg1)
    modelAndView.addObject("message", "helloworldttt@$@!^&&%9966!!!!");
    //指定jsp页面地址
    //指定逻辑视图名,真正的视图地址:前缀+逻辑视图名+后缀
    modelAndView.setViewName("hello");
    return modelAndView;
    }
    }
     
    ②形式 HttpRequestHandlerAdapter
    HttpRequestHandlerAdapter:规则是Handler要实现HttpRequestHandler接口。
    <!-- 配置HttpRequestHandlerAdapter处理器适配器 -->
    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
    public class Hello1 implements HttpRequestHandler {
     
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
     
    //向页面显示一行提示信息
    String message = "hellworld1";
    request.setAttribute("message", message);
     
    //指定转向页面,使用request指定页面完整路径
    request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(request, response);
     
    }
     
    }
     
    ③ 注解适配器形式
    <!--注解适配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
     
    ④<mvc:annotation-driven />代替注解适配器
     
    mvc的注解驱动
    <mvc:annotation-driven />默认注册了注解映射器和注解适配器等bean
     
    mvc组件扫描
    <context:component-scan base-package="springmvc.action" />
    扫描@component@controller@service@repository的注解
    注意:如果使用组件扫描则controller不需要在springmvc-servlet.xml中配置
     
     
     
    视图解析器:
    InternalResourceViewResolver
     
    <!-- 视图解析器 解析jsp视图,默认使用jstl,要求classpath下有jstl的jar包 -->
    <bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 视图的前缀 -->
    <property name="prefix" value="/WEB-INF/jsp/" />
    <!-- 视图的后缀 -->
    <property name="suffix" value=".jsp" />
    </bean>
     
     
     
     
     
    <mvc:annotation-driven />
    是一种简写形式,替换掉适配器、映射器
     
    <context:component-scan base-package="com.roof" />
    自动扫描bean
    例子:
    <!-- 扫描所有的controller 但是不扫描service -->
    <context:component-scan base-package="cn.itcast">
    <context:include-filter type="annotation"
    expression="org.springframework.stereotype.Controller" />
    <context:exclude-filter type="annotation"
    expression="org.springframework.stereotype.Service" />
    </context:component-scan>
     
    org.springframework.context.support.ResourceBundleMessageSource
    注册到bean.xml中,这个类的作用是获取资源文件的内容,注册到IoC的bean.xml文件中是为了自动获得此类的对象
     
    org.springframework.web.multipart.commons.CommonsMultipartResolver
     
    @Entity
    标注该类为实体类。
     
    @Table(name = "sys_user")
    @Table注释指定了Entity所要映射带的据库表
     
     
    Controller方法通过形参接收页面传递的参数。
    如下:
    @RequestMapping("/userlist")
    public String userlist(HttpServletRequest request,
    HttpServletResponse response,
    HttpSession session,
    Model model
    ){
    }
     
    默认支持的参数类型
    HttpServletRequest
    通过request对象获取请求信息
    HttpServletResponse
    通过response处理响应信息
    HttpSession
    通过session对象得到session中存放的对象
    Model
    通过model向页面传递数据,如下:
     
    model.addAttribute("user", new User("李四"));
     
    页面通过${user.XXXX}获取user对象的属性值。
     
    springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。简而言之就是,从把jsp页面的数据,以对象的形式可以在后台获取到。前提是jsp的中的名称和model的名称是一致的。页面上以pojo对象中属性名称命名
     
     
     
     
        表单对象-pojo
    1.1.1      使用pojo属性名传递
    页面定义:
     
    Action方法的定义:
     
    在形参使用pojo接收上边的参数。
     
    1.1.2      使用pojo点属性名传递
    页面定义:
     
    Action方法的定义:
    在形参不能直接使用pojo接收上边的参数。
    应该使用包装对象接收上边的参数。
     
     
    Action形参的定义:
     
    字符串数组绑定
    需求:在学生列表上多选,删除学生信息。
     
    页面定义:
     
     
    Action方法定义:
    使用字符串数组接收。
    批量删除学生信息方法,接收页面复选框的值(学生id
     
     
    List绑定
     
    页面向action传递复杂的批量数据,比如学生的成绩信息(课程名称、成绩)
    页面定义:
     
     
     
    Scores:包装对象中list属性的名称
    Coursename:包装对象中list中pojo的属性名称。
    Score:包装对象中list中pojo的属性名称。
    如果上边下标相同的Coursename和Score设置在一个pojo中。
     
    Action方法定义:
    使用List<pojo>接收上边的接收,pojo中包括上边课程名称(coursename)和成绩(score)
    List通过包装对象接收。
     
    在UserVo包装中定义属性:List<>
     
    Action方法形参使用包装对象接收list
     
     
    @RequestMapping
    URL路径映射
    @RequestMapping(value="/user")或@RequestMapping("/user")
    根路径+子路径
    根路径:
    @RequestMapping放在类名上边,如下:
    @Controller
    @RequestMapping("/user")
    子路径:
    @RequestMapping放在方法名上边,如下:
    @RequestMapping("/useradd")
    public String useradd(….
     
    URI 模板模式映射
    @RequestMapping(value="/useredit/{userId}"):{×××}占位符,请求的URL可以是“/useredit/001”或“/useredit/abc”,通过在方法中使用@PathVariable获取{×××}中的×××变量。
     
    例如:
    // 修改学生信息页面
    // @RequestMapping指定url
    @RequestMapping(value="/editstudent/{id}",method = RequestMethod.GET)
    public String editstudent(HttpServletRequest request,Model model,@PathVariable String id) throws Exception {
    System.out.println("id="+id);
    ......
    jsp页面上
    <td><a href="editstudent/${stu.id }.action">修改</a></td>
     
    实现restFul,所有的url都是一个资源的链接,有利于搜索引擎对网址收录。
     
    多个占位符:
     
    @RequestMapping("/useredit/{groupid}/{userid}")
    public String useredit(@PathVariable String groupid,@PathVariable String userid,Model model) throws Exception{
    //方法中使用@PathVariable获取useried的值,使用model传回页面
    model.addAttribute("groupid", groupid);
    model.addAttribute("userid", userid);
    return"/user/useredit";
    }
     
    请求方法限定
    限定GET方法
    @RequestMapping(method = RequestMethod.GET)
     
    如果通过Post访问则报错:
    HTTP Status 405 - Request method 'POST' not supported
     
    例如:
    @RequestMapping(value="/useredit/{userid}",method=RequestMethod.GET)
    限定POST方法
     
    @RequestMapping(method = RequestMethod.POST)
     
    如果通过Post访问则报错:
    HTTP Status 405 - Request method 'GET' not supported
     
    GET和POST都可以
    @RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
     
     
    @RequestParam绑定单个请求参数
     
    value:参数名字,即入参的请求参数名字,如value=“studentid”表示请求的参数区中的名字为studentid的参数的值将传入;
    required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
    defaultValue:默认值,表示如果请求中没有同名参数时的默认值
     
    定义如下:
    public String userlist( @RequestParam(defaultValue="2",value="group",required=true) String groupid) {=
    }
    形参名称为groupid,但是这里使用value="group"限定参数名为group,所以页面传递参数的名必须为group。
    这里通过required=true限定groupid参数为必需传递,如果不传递则报400错误,由于使用了defaultvalue=”2”默认值即使不传group参数它的值为”2”,所以页面不传递group也不会报错,如果去掉defaultvalue=”2”且定义required=true则如果页面不传递group则会报错。
     
    结果转发
    Redirect
    //请求重定向
    Contrller方法返回结果重定向到一个url地址,如果方式:
    return "redirect:/user/userlist.action";
     
     
    redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。
    由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/user/userlist.action后边加参数,如下:
    /user/userlist.action?groupid=2&…..
     
    forward
    //页面转发
    controller方法执行后继续执行另一个controller方法。
    return "forward:/user/userlist.action";
     
    forward方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到。
     
    如下例子:
     
    @RequestMapping("/c")
    public String c(String groupid,UserVo userVo)throws Exception{
     
    System.out.println("...c...."+groupid+"...user..."+userVo.getUser());
    return "forward:/to/d.action";
    }
     
    @RequestMapping("/d")
    public String d(String groupid,UserVo userVo)throws Exception{
     
    System.out.println("...d...."+groupid+"...user..."+userVo.getUser());
    return "success";
    }
     
    @RequestBody @ResponseBody实现json数据交互
    可以使用@RequestBody将请求的json串转成java对象。
    使用@ResponseBody将action方法返回java对象转成json输出。
     
    请求json响应json 
     
    <!--注解适配器 -->
    <bean
    class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    json转换器
    <property name="messageConverters">
    <list>
    <bean
    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
    </list>
    </property>
     
    </bean>
     
    如果使用 了<mvc:annotation-driven />则替换上边定义的处理器映射器和适配器 -->
     
     
     
    1       拦截器
     
    拦截器是针对handlerMapping的拦截器,由handlerMapping查找Handler后,将拦截器返回给前端控制器。
     
    1.1      配置拦截器
     
    针对某一个handlerMapping配置拦截器
    <bean
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
        <property name="interceptors">
           <list>
               <ref bean="handlerInterceptor1"/>
               <ref bean="handlerInterceptor2"/>
           </list>
        </property>
    </bean>
        <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
        <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
     
     
     
     
    间接配置全局拦截器:让springmvc框架自动向每个handlerMapping中注册拦截器
    <!--拦截器 -->
    <mvc:interceptors>
        <!--多个拦截器,顺序执行 -->
        <mvc:interceptor>
           <mvc:mapping path="/**"/>//拦截所有请求
           <bean class="cn.itcast.springmvc.interceptor.HandlerInterceptor1"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
           <mvc:mapping path="/**"/>
           <bean class="cn.itcast.springmvc.interceptor.HandlerInterceptor2"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
     
     
     
    1.2      定义拦截器
    实现HandlerInterceptor接口。
     
    public class HandlerInterceptor1 implements HandlerInterceptor {
     
       //handlerspringmvc根据url找到Handler(只有一个方法)
       //执行时机:进入Handler方法之前执行,如果返回false表示拦截,如果返回true表示放行
       //使用场景:用于用户身份校验,用户权限拦截校验
       @Override
       public boolean preHandle(HttpServletRequest request,
             HttpServletResponse response, Object handler) throws Exception {
         
          System.out.println("HandlerInterceptor1..preHandle");
         
          return false;
       }
       //执行时机:进入Handler方法之后 ,在返回modelAndView之前
       //使用场景:使用modelAndView,向页面传递通用数据,使用统一的view
       @Override
       public void postHandle(HttpServletRequest request,
             HttpServletResponse response, Object handler,
             ModelAndView modelAndView) throws Exception {
          System.out.println("HandlerInterceptor1..postHandle");
         
       }
       //执行时机:Handler方法执行完成,(modelAndView已经返回)
       //使用场景:统一异常处理,统一记录系统日志,用于action方法执行监控(在preHandle记录一个时间点,在afterCompletion记录执行结束时间点,将结束时间点减去开始执行时间点,得到执行时长)
       @Override
       public void afterCompletion(HttpServletRequest request,
             HttpServletResponse response, Object handler, Exception ex)
             throws Exception {
          System.out.println("HandlerInterceptor1..afterCompletion");
         
       }
     
     
    1.3      测试
     
    1.3.1      两个拦截器都放行
     
    HandlerInterceptor1..preHandle
    HandlerInterceptor2..preHandle
    HandlerInterceptor2..postHandle
    HandlerInterceptor1..postHandle
    HandlerInterceptor2..afterCompletion
    HandlerInterceptor1..afterCompletion
     
    结论:
    preHandle是按照拦截器定义顺序执行,
    postHandleafterCompletion是按照拦截器定义逆向执行。
     
     
    1.3.1      第一个放行第二个不放行
    HandlerInterceptor1..preHandle
    HandlerInterceptor2..preHandle
    HandlerInterceptor1..afterCompletion
     
    结论:
    只要有一个拦截器不放行,action方法无法完成。
    如果拦截器放行,afterCompletion才会执行。
    只要有一个拦截器不放行,postHandle不执行。
     
    1.3.2      两个都不放行
     
    HandlerInterceptor1..preHandle
     
    结论:
    只要有一个拦截器不放行,action方法无法完成。
    只要有一个拦截器不放行,postHandle不执行。
     
     
     
    1.4      拦截器应用
     
    案例:
    用户身份认证拦截,用户登陆成功后,系统记录session(用户身份信息),用户去操作url时,拦截器需要校验用户身份是否合法(查看session中是否有用户身份信息,如果没有说明用户身份不合法,不合法重新登陆)
     
     
    1.4.1      action
    @Controller
    public class LoginAction {
      
       //登陆页面
       @RequestMapping("/login")
       public String login(Model model)throws Exception{
         
          return "login";
       }
      
       //登陆提交
       //userid:用户账号,pwd:密码
       @RequestMapping("/loginsubmit")
       public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{
         
          //session记录用户身份信息
          session.setAttribute("activeUser", userid);
         
          return "redirect:stu/querystudent.action";
       }
      
       //退出
       public String logout(HttpSession session)throws Exception{
         
          //session过期
          session.invalidate();
         
          return "redirect:stu/querystudent.action";
       }
      
     
    }
     
    1.4.2      页面
     
    @Controller
    public class LoginAction {
      
       //登陆页面
       @RequestMapping("/login")
       public String login(Model model)throws Exception{
         
          return "login";
       }
      
       //登陆提交
       //userid:用户账号,pwd:密码
       @RequestMapping("/loginsubmit")
       public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{
         
          //session记录用户身份信息
          session.setAttribute("activeUser", userid);
         
          return "redirect:stu/querystudent.action";
       }
      
       //退出
    @RequestMapping("/logout")
       public String logout(HttpSession session)throws Exception{
         
          //session过期
          session.invalidate();
         
          return "redirect:stu/querystudent.action";
       }
      
     
    }
     
    1.4.3      拦截器
     
    拦截所有url(将公开地址排除(无需登陆即可操作的url)),校验用户身份是否合法(查看session中是否有用户身份信息,如果没有说明用户身份不合法,不合法重新登陆)
     
    @Override
       public boolean preHandle(HttpServletRequest request,
             HttpServletResponse response, Object handler) throws Exception {
         
          //判断请求的url是否公开 地址(无需登陆即可操作url)
          //正常开发时,需要将公开地址配置在配置文件中。
          //取出请求的url
          String url = request.getRequestURI();
          if(url.indexOf("loginsubmit.action")>=0){
             //说明 公开地址
             //放行
             return true;
          }
         
         
          //得到session
          HttpSession session = request.getSession();
         
          // session取出用户身份信息
          String userid = (String) session.getAttribute("activeUser");
         
          if(userid!=null){
             //说明 用户已登陆(用户身份合法)
             //放行
             return true;
            
          }
         
          //执行到这里说明 用户身份不合法,拦截,跳转到登陆页面
          request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
     
          return false;
       }
     
     
    1.1      拦截器应用
     
    案例:
    用户身份认证拦截,用户登陆成功后,系统记录session(用户身份信息),用户去操作url时,拦截器需要校验用户身份是否合法(查看session中是否有用户身份信息,如果没有说明用户身份不合法,不合法重新登陆)
     
     
    1.1.1      action
    @Controller
    public class LoginAction {
      
       //登陆页面
       @RequestMapping("/login")
       public String login(Model model)throws Exception{
         
          return "login";
       }
      
       //登陆提交
       //userid:用户账号,pwd:密码
       @RequestMapping("/loginsubmit")
       public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{
         
          //session记录用户身份信息
          session.setAttribute("activeUser", userid);
         
          return "redirect:stu/querystudent.action";
       }
      
       //退出
       public String logout(HttpSession session)throws Exception{
         
          //session过期
          session.invalidate();
         
          return "redirect:stu/querystudent.action";
       }
      
     
    }
     
    1.1.2      页面
     
    @Controller
    public class LoginAction {
      
       //登陆页面
       @RequestMapping("/login")
       public String login(Model model)throws Exception{
         
          return "login";
       }
      
       //登陆提交
       //userid:用户账号,pwd:密码
       @RequestMapping("/loginsubmit")
       public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{
         
          //session记录用户身份信息
          session.setAttribute("activeUser", userid);
         
          return "redirect:stu/querystudent.action";
       }
      
       //退出
    @RequestMapping("/logout")
       public String logout(HttpSession session)throws Exception{
         
          //session过期
          session.invalidate();
         
          return "redirect:stu/querystudent.action";
       }
      
     
    }
     
    1.1.3      拦截器
     
    拦截所有url(将公开地址排除(无需登陆即可操作的url)),校验用户身份是否合法(查看session中是否有用户身份信息,如果没有说明用户身份不合法,不合法重新登陆)
     
    @Override
       public boolean preHandle(HttpServletRequest request,
             HttpServletResponse response, Object handler) throws Exception {
         
          //判断请求的url是否公开 地址(无需登陆即可操作url)
          //正常开发时,需要将公开地址配置在配置文件中。
          //取出请求的url
          String url = request.getRequestURI();
          if(url.indexOf("loginsubmit.action")>=0){
             //说明 公开地址
             //放行
             return true;
          }
         
         
          //得到session
          HttpSession session = request.getSession();
         
          // session取出用户身份信息
          String userid = (String) session.getAttribute("activeUser");
         
          if(userid!=null){
             //说明 用户已登陆(用户身份合法)
             //放行
             return true;
            
          }
         
          //执行到这里说明 用户身份不合法,拦截,跳转到登陆页面
          request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
     
          return false;
       }
  • 相关阅读:
    UVa 1151 Buy or Build【最小生成树】
    UVa 216 Getting in Line【枚举排列】
    UVa 729 The Hamming Distance Problem【枚举排列】
    HDU 5214 Movie【贪心】
    HDU 5223 GCD
    POJ 1144 Network【割顶】
    UVa 11025 The broken pedometer【枚举子集】
    HDU 2515 Yanghee 的算术【找规律】
    Java基本语法
    Java环境变量,jdk和jre的区别,面向对象语言编程
  • 原文地址:https://www.cnblogs.com/YangBinChina/p/8966341.html
Copyright © 2011-2022 走看看