• SpringMVC 入门


    1. HelloWorld 入门程序

    // 1. 导入 jar 包;
    
    // 2. 配置 WEB-INF/web.xml
    
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    // 3. 在WEB-INF创建springDispatcherServlet-servlet.xml 配置文件
    //      选择: spring Bean Configuration File, 名称, beans, context, mvc,   完成
    <!-- 配置通用扫描的包路径 -->
    <context:component-scan base-package="cn.itcast.springmvc"></context:component-scan>
    
    <!-- 配置通用的视图解析器 -->
    <bean id="internalResourceViewResolver"
                class="org.springframework.web.servlet.view.internalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
    
    // 3.1 也可以在 src 目录下,创建SpringMVC的配置文件, 此时,web.xml 的配置为:
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <!-- 配置springmvc 配置文件路径 -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servet-mapping>
    
    
    // 4. 创建WEB-INF/views/ok.jsp, 即结果页面
    
    // 5. 创建WebContent/index.jsp, 即请求页面
    示例:<a href="${pageContext.request.contextPath}/helloworld">点击这里</a>
    
    // 6. cn.itcast.springmvc.handler(或controller)
    @Controller
    public class HelloWorld{
    
        @RequestMapping(value="/helloworld",method=RequestMethod.GET)
        public String helloworld(){
            System.out.println("程序运行正常");
            return "ok";
        }
    }
    

    2. HelloWorld 深度解析

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

    3. 注解 RequestMapping

    3.1 请求地址

    @Controller
    @RequestMapping(value="/crm")
    public class HelloWorld{
    
        @RequestMapping(value="/helloworld",method=RequestMethod.GET)
        public String helloworld(){
            System.out.println("程序运行正常");
            return "ok";
        }
    }
    
    // 备注: 此时访问地址: /crm/helloworld
    

    3.2 RequestMapping 中的参数介绍

    1. 常用方法:
      • method=RequestMethod.GET
      • method=RequestMethod.POST
    2. 请求参数映射 params
      • params={"age","tel!=110"}
      • 表示请求参数中必须有age和tel,且tel不是110;
    3. 请求头映射 headers
      • headers={"Host=localhost:8080"}
      • 表示请求主机必须是 localhost:8080;
    4. URL 映射
    // 1. 占位符URL映射
        // ? 匹配一个字符; * 匹配零个或多个字符; ** 匹配零个或多个路径
        public class Demo{
    
            @RequestMapping(value="/test?", method=RequestMethod.GET)
            public String test(){
                System.out.println("程序运行正常");
                return "ok";
            }
        }
    
    // 2. @PathVariable 占位符URL映射
        // index.jsp
        示例: <a href="${pageContext.request.contextPath}/tpv/887">testPathVariable</a>
    
        // cn.itcast.springmvc.demo
        @Controller
        public class Demo{
    
            @RequestMapping(value="/tpv/{bookId}",method=RequestMethod.GET)
            public String test2(@PathVariable("bookId") String bookId){
                System.out.println("程序运行正常"+bookId);
                return "ok";
            }
        }
    

    4. REST 介绍

    1. REST, Representational State Transfer, (资源)表现层状态转化;
    2. 资源:网络上的一个具体信息,可以是一段文本,一张图片等等;每种资源对应一个特定的URI,要获取这个资源,
      访问它的 URI 即可, 因此, URI 即为每一个资源的独一无二的识别符;
    3. 表现层: 把资源具体呈现出来的形式; 例如文本可以用txt格式表现,也可以用HTML格式,XML格式或JSON格式
    4. 状态转化:每发出一个请求,就代表了客户端和服务器的一次交互过程. HTTP协议,是一个无状态协议,即所有
      的状态都保存在服务端.因此,如果客户端想要操作服务器,必须通过某种手段,让服务器发生"状态转化".而
      这种转化是建立在表现层之上的,所以就是"表现层状态转化".具体说,就是HTTP协议里面,四个表示操作方式
      的动词: GET,POST,PUT,DELETE,分别对应四种基本操作: GET 用来获取资源, POST 用来新建资源,
      PUT 用来更新资源, DELETE 用来删除资源;
    // 需求: 发送RESTful风格请求
    // 1. web.xml 中配置 HiddenHttpMethodFilter
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    // 2. index.jsp
    <form action="${pageContext.request.contextPath}/order/224" method="post">
        <input type="hidden" name="_method" value="DELETE"/>
        <input type="submit" value="删除订单"/>
    </form>
    
    // 3. cn.itcast.springmvc.demo
    @Controller
    public class Demo{
    
        @RequestMapping(value="/order/{orderId}",method=RequestMethod.DELETE)
        public String delete(@PathVariable("orderId") String orderId){
            System.out.println("删除订单成功"+orderId);
            return "ok";
        }
    }
    

    5. 获取请求相关数据

    • @RequestParam
    • @PathVariable
    • @RequestHeader
    • @CookieValue
    // @RequestParam, 获取请求参数
    // index.jsp
    <a href="${pageContet.reqeust.contextPath}/testRequestParam?name=zhangsan">点击这里</a>
    
    // cn.itcast.springmvc.demo
    @Controller
    public class Demo{
    
        @RequestMapping(value="/testRequestParam",method=RequestMethod.GET)
        public String testRequestParam(@RequestParam("name") String name){
    
            System.out.println("姓名:"+name);
            return "ok";
        }
    
        // @RequestParam 中的参数: required, defaultValue
        @RequestMapping(value="/testRequestParam",method=RequestMethod.GET)
        public String test03(@RequestParam(value="name",required=true,
                                                    defaultValue="lisi")  String name){
    
            System.out.println("姓名:"+name);
            return "ok";                
        }
    }
    
    // 请求中有多个参数
    // index.jsp
    <a href="${pageContext.request.contextPath}/test04?name=zhangsan&roleId=manager&roleId=actory">
    点击这里
    </a>
    
    // demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test04",method=RequestMethod.GET)
        public String test04(@RequestParam(value="name") String name,
                             @RequestParam("roleId") List<String> roleIds){
    
            for(String rId : roleIds){
                System.out.println(rId);
            }
            System.out.println(name);
            return "ok";
        }
    }
    
    
    // @RequestHeader, 获取请求头的值
    // @CookieValue, 获取 cookie 的值
    // index.jsp
    <a href="${pageContext.request.contextPath}/test05">点击这里</a>
    
    // demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test05",method=RequestMethod.GET)
        public String test05(@RequestHeader("Host") String host,
                             @CookieValue("JSESSIONID") String JSESSIONID){
            System.out.println(host + JSESSIONID);
            return "ok";
        }
    }
    
    
    // 使用 POJO 对象
    // User.class(略)
    // index.jsp
    <form action="${pageContext.request.contextPate}/test06" method="post">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        <input type="submit" value="注册"/>
    </form>
    
    // demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test06",method=RequestMethod.POST)
        public String test06(User user){
            System.out.println(user);
            return "ok";
        }
    }
    
    
    // 使用Servlet的原生API获取参数
    // test06() 中的参数: HttpServletRequest, HttpServletResponse,HttpSession,
    //                   java.security.Principal, Locale, InputStream, OutputStream,
    //                   Reader, Writer
    
    // index.jsp(略)
    // demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test07",method=RequestMethod.GET)
        public void test06(HttpServletRequest request, HttpServletResponse response,
                                             Writer writer) throws IOException{
    
            System.out.println(request.getContextPath());
            writer("程序运行正常");
            wirter.close();
        }
    }
    

    6. 处理模型数据

    6.1 ModelAndView

    • SpringMVC 框架会将 ModelAndView 中的数据放进request请求域中, ModelAndView 底层实际就是
      request.setAttribute(k,v);
    // index.jsp
    <a href="${pageContext.request.contextPath}/test07">点击这里</a>
    
    // demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test07", method=RequestMethod.GET)
        public ModelAndView test07(){
            ModelAndView mv = new ModelAndView();
            mv.addObject("username","zhangsan");
            mv.setViewName("ok");
            return mv;
        }
    }
    
    // ok.jsp
    用户名:${requestScope.username}
    

    6.2 Map+Model+ModelMap

    • Map: java.util.Map, 接口;
    • Model: org.springframework.ui.Model, 接口;
    • ModelMap: org.springframework.ui.ModelMap, 实现类;
    // index.jsp
    <a href="${pageContext.request.contextPath}/test08">点击这里</a>
    
    // demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test08",method=RequestMethod.GET)
        public String test08(Map<String,Object> m1, Model m2, ModelMap m3){
    
            m1.put("m1","java.util.Map<K,V>");
            m2.addAttribute("m2","org.springframework.ui.Model");
            m3.addAttribute("m3","org.springframework.ui.ModelMap");
    
            System.out.println(m1 == m2);
            System.out.println(m2 == m3);
            System.out.println(m1 == m3);
    
            System.out.println(m1.getClass().getName());
            System.out.println(m2.getClass().getName());
            System.out.println(m3.getClass().getName());
    
            return "ok";
        }
    }
    
    // ok.jsp
    m1: ${requestScope.m1}<br/>
    m2: ${requestScope.m2}<br/>
    m3: ${requestScope.m3}<br/>
    

    6.2.1 结果说明
    • 此处虽然注入的是三个不同的类型(Map m1, Model m2, ModelMap m3), 但三者是同一个对象,都是
      同一个BindingAwareModelMap实例;
    • SpringMVC 框架会将模型数据放进request请求域中;
    • 为了方便重构,使用java.util.Map较多;

    6.3 SessionAttributes

    • 该注解只能放在类上面;
    // index.jsp
    <a href="${pageContext.request.contextPath}/test09">点击这里</a>
    
    // demo.class
    @Controller
    @SessionAttributes(value="user",types=String.class)
    public class Demo{
    
        @RequestMapping(value="/test09",method=RequestMethod.GET)
        public String test09(Map<String,Object> map){
    
            User user = new User("zhangsan",22,"zhangsan@163.com");
            map.put("user",user);
    
            map.put("address","Beijing");
            return "ok";
        }
    }
    
    // ok.jsp
    用户名: ${sessionScope.user}
    地址: ${sessionScope.address}
    

    6.4 ModelAttribute

    • 该注解作用在:方法或参数上, @Target({ElementType.PARAMETER, ElementType.METHOD})

    // 需求: 用户李四将自己的用户名改为"zhangsan",年龄改为"25",密码和邮箱不变
    // index.jsp
    <h2>修改信息</h2>
    <form action="${pageContext.request.contextPath}/test10" method="post">
        <input type="hidden" name="_method" value="PUT"/><br/>
        <input type="hidden" name="id" value="11"/><br/>
        用户名:<input type="text" name="username" value="zhangsan"/><br/>
        年龄: <input type="text" name="age" value="22"/><br/>
        Email: <input type="text" name="email" value="zhangsan@163.com"/><br/>
        <input type="submit" value="修改"/><br/>
    </form>
    
    // demo.class
    @Controller
    @SessionAttributes(value="user")
    public class Demo{
    
        @RequestMapping(value="/test10",method=RequestMethod.PUT)
        public String test10(User user){
            System.out.println(user);
            return "ok";
        }
    }
    
    6.4.1 异常一: "Session attribute 'user' required - not found in session"
    • 解决方法: 将@SessionAttributes(value="user")注释掉;

    6.4.2 异常二: 此时,收到的password=null

    // 修改 demo.class
    @Controller
    public class Demo{
    
        @RequestMapping(value="/test10",method=RequestMethod.PUT)
        public String test10(User user){
            Sysetm.out.println("修改之后的User: "+ user);
            return "ok";
        }
    
        // 从数据库中根据 id 查询
        @ModelAttribute
        public void getUserById(@RequestParam(value="id") Integer id){
            System.out.println("come in @ModelAttribute ##############");
    
            if(null != id){
    
                // 模拟根据 id,从数据库查询出对应的 User 信息
                // User user = UserService.getUserById(id);
                // user(id,name,password,age,email);
                User user = new User(11,"lisi","12345",22,"lisi@163.com");
                System.out.println("数据库查询到的初始User: "+ user);
            }
        }
    }
    
    运行结果, 另外,点击其他请求,出现如下异常:"Required Integer parameter 'id' is not present"

    结果分析
    // 修改代码, 增加属性 `required=false`,将数据库查询到 user,存入到隐藏域
    
    @ModelAttribute
    public void getUserById(@RequestParam(value="id", required=false) Integer id,
                                                        Map<String,Object> map){
        System.out.println("come in @ModelAttribute ##############");
    
        if(null != id){
    
            // 模拟根据 id,从数据库查询出对应的 User 信息
            // User user = UserService.getUserById(id);
            // user(id,name,password,age,email);
            User user = new User(11,"lisi","12345",22,"lisi@163.com");
    
            // 将user放入隐藏域
            map.put("user",user);
    
            System.out.println("数据库查询到的初始User: "+ user);
        }
    }
    
    运行结果

    总结一:
    1. 根据ID从数据库中查询出对象,并将对象放入Map,其中key为user(POJO类名首字母小写),完成修改;
    2. 在方法头上添加 @ModelAttribute
      • 每个 Controller 类下面的业务方法都会先调用标注了@ModelAttribute注解的方法;
      • 放入到Map的 key,需要与目标方法的参数首字母小写的对象一致;
    3. 在方法入参前使用 @ModelAttribute
      • 查询数据库放入map的 key与 @ModelAttribute修改的方法入参前名字,是否一致;不一致; 不写;
    // 第一种方式: 在方法入参前,使用 @ModelAttribute("user"), 即与隐藏域map中的key名称一致
    @RequestMapping(value="test10",method=RequestMethod.PUT)
    public String test10(@ModelAttribute("user") User user){
        System.out.println("修改之后的User: "+user);
        return "ok";
    }
    
    // 第二种方式:在方法入参前,使用 @ModelAttribute("abc"),即与隐藏域map中的key名称不一致;
    // 此时,password 为 null;
    @RequestMapping(value="test10",method=RequestMethod.PUT)
    public String test10(@ModelAttribute("abc") User user){
        System.out.println("修改之后的User: "+user);
        return "ok";
    }
    
    @ModelAttribute
    public void getUserById(@RequestParam(value="id",required=false) Integer id,
                                                    Map<String,Object> map){
            System.out.println("come in @ModelAttribute #######");
            if(null != id){
                User user = new User(11,"lisi","12345",22,"lisi@163.com");
            }
    
            map.put("user",user);
    
            System.out.println("数据库查询到的初始User: "+user);
        }
    

    总结二:
    1. 确定key的值,如果有@ModelAttribute进行修饰,则key的值就是@ModelAttribute注解的value属性值;
      如果没有写,默认key值就是传入POJO类名的第一个字母小写;
    2. 从Map中获取key对应的Bean,如果有,就直接赋值并作为后续入参传入;
      如果没有,那就去Session域中查找,也就是当前Handler的@SessionAttributes注解的value值或者
      types值是否和key或者Bean的类型匹配,如果匹配就从Session域中获取;
      • 如果Session中有对象,则返回该值作为目标方法的入参;
      • 如果Session中没有对象,就会抛出异常 HttpSessionRequiredException;
    3. 如果implictModel中没有,sessionAttribute中也没有,那就通过反射创建一个 bindObject,
      bindObject = BeantUtils.instantiateClass(paramType);

    参考资料

  • 相关阅读:
    UVA-10917 Walk Through the Forest (dijkstra+DP)
    UVA-11374 Airport Express (dijkstra+枚举)
    UVA-11294 Wedding (2-SAT)
    UVALive-3713 Astronauts (2-SAT)
    UVALive-3211 Now or later (2-SAT+二分)
    线程变量
    linux通用双向链表
    排序算法代码
    双向链表
    long与int的区别?(zz)
  • 原文地址:https://www.cnblogs.com/linkworld/p/7766460.html
Copyright © 2020-2023  润新知