Spring MVC

MVC框架

image-20221113210005188

Spring MVC常用组件

image-20221113203426305

Spring MVC项目

  • 浏览器发送一个请求,若请求地址与 web.xml 中配置的前端控制器(DispatcherServlet)的 url-pattern 相匹配,则该请求就会被前端控制器 DispatcherServlet 拦截;
  • 前端控制器(DispatcherServlet )会读取 SpringMVC 的核心配置文件,通过组件扫描获取到所有的控制器(Contorller);
  • 将请求信息和控制器中所有控制器方法标识的 @RequestMapping 注解的 value、method 等属性值进行匹配。若匹配成功,则将请求交给对应的 @RequestMapping 注解所标识的控制器方法处理;
  • 处理请求的方法会返回一个字符串类型的视图名称,该视图名称会被 Spring MVC 配置文件中配置的视图解析器(ViewResolver)解析真正的视图(View)对象,最终展示给客户端。
package net.biancheng.c.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
    @RequestMapping("/")
    public String sayHello() {
        //视图名,视图为:视图前缀+index+视图后缀,即 /WEB-INF/template/index.html
        return "index";
    }
    @RequestMapping("/login")
    public String welcome() {
        //视图名,视图为:视图前缀+login+视图后缀,即 /WEB-INF/template/login.html
        return "login";
    }
    @RequestMapping("/register")
    public String success() {
        //视图名,视图为:视图前缀+register+视图后缀,即 /WEB-INF/template/register.html
        return "register";
    }
}

SpringMVC执行流程

image-20221113210321765

@RequestMapping注解

  • 使用方式

    • 修饰方法:要访问该方法,请求路径必须与这个value值相同
    • 修饰类:要访问类中的任意方法,都要带上这个父路径
  • 属性

    • value属性:用于设置请求地址

    • name属性:用于注释

    • method属性:method 属性的取值是一个 RequestMethod 类型的数组,表示一个控制器方法支持多种方式的请求,常用的请求方式有 GET、POST、DELETE、PUT 等。如果一个控制器方法没有设置 @RequestMapping 注解的 method 属性,则说明该控制器方法支持全部请求类型,可以处理所有类型的请求。

    • params属性:取值是一个字符串类型的数组,用于指定请求中的参数,只有当请求中携带了符合条件的参数时,控制器方法才会对该请求进行处理

      image-20221113211532567

      @RequestMapping(value = "/testParam", params = {"name=z5onk0", "url=http://www.baidu.com"})
      @ResponseBody
      public String testParam() {
          return "success";
      }
      //以上代码表示,只有当请求中同时携带 name 和 url 两个请求参数,且参数值必须分别为 “z5onk0” 和“http://www.baidu.com”时,控制器方法 testParam() 才会对该请求进行处理 。
      
    • headers属性:取值是一个字符串类型的数组,用于设置请求中请求头信息,只有当请求中携带指定的请求头信息时,控制器方法才会处理该请求

Spring MVC获取请求参数

  • 通过HttpServletRequest

    @RequestMapping("/getRequestParam")
        public String requestParam(HttpServletRequest request) {
        String name = request.getParameter("name");
        String url = request.getParameter("url");
        System.out.println("name:" + name);
        System.out.println("url:" + url);
        return "index";
    }
    
  • 通过形参获取:在 Controller 的控制器方法中设置与请求参数同名的形参,以获取请求中携带的参数。需要注意这种方式是无视参数的数据类型的,我们可以在控制器方法中使用 String 字符串类型的形参接收所有的请求参数;并且不适用于参数过多的情况

    @RequestMapping("/test")
    public String test(String name, String language) {
        System.out.println("a:" + a);
        System.out.println("b:" + b);
        return "success";
    }
    
  • 通过实体类对象获取(推荐):在 Controller 控制器方法的形参中设置一个实体类形参,如果请求参数的参数名与实体类中的属性名一致,那么 Spring MVC 会自动将请求参数封装到该实体类对象中

    • 在net.biancheng.c.entity 包下,创建一个名为 User 的实体类

      package net.biancheng.c.entity;
      public class User {
          private String UserId;
          private String UserName;
          private Integer age;
          public String getUserId() {
              return UserId;
          }
          public void setUserId(String userId) {
              UserId = userId;
          }
          public String getUserName() {
              return UserName;
          }
          public void setUserName(String userName) {
              UserName = userName;
          }
          @Override
          public String toString() {
              return "User{" +
                      "UserId='" + UserId + '\'' +
                      ", UserName='" + UserName + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
      
    • 创建一个名为 UserController 的 Controller 类

      package net.biancheng.c.controller;
      import net.biancheng.c.entity.User;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      @Controller
      public class UserController {
          /**
           * 通过实体类获取请求参数
           *
           * @param user
           * @return
           */
          @RequestMapping("/getUser")
          public String getUser(User user) {
              System.out.println("userId:" + user.getUserId());
              System.out.println("userName:" + user.getUserName());
              System.out.println("password:" + user.getPassword());
              return "success";
          }
      }
      

Spring MVC域对象共享

  • Controller 在接收到 Model 层返回的模型数据后,下一步就是将模型数据通过域对象共享的方式传递给 View 视图进行渲染,最终返回给客户端展示

  • 域对象是服务器在内存上创建的一块存储空间,主要用不同动态资源之间的数据传递和数据共享。在 Spring MVC 中,常用的域对象有 request 域对象、session 域对象、application 域对象等

  • 方式:

    • 使用 Servlet API 向 request 域对象中共享数据

      @RequestMapping("/testServletAPI")
      public String testServletAPI(HttpServletRequest request) {
          request.setAttribute("testScope", "hello,Servet API");
          return "success";
      }
      
    • 使用 ModelAndView 向 request 域对象中共享数据

      • model 负责数据共享,而 view 则主要用于设置视图,实现页面的跳转

        image-20221114200112232

        @RequestMapping("/testModelAndView")
        public ModelAndView testModelAndView() {
             /**
             * ModelAndView有Model和View的功能
             * Model主要用于向请求域共享数据
             * View主要用于设置视图,实现页面跳转
             */
            ModelAndView mav = new ModelAndView();
            //向请求域共享数据
            mav.addObject("testScope", "hello,ModelAndView");
            //设置视图,实现页面跳转
            mav.setViewName("success");
            return mav;
        }
        
    • 使用 Map 向 request 域对象中共享数据

      @RequestMapping("/testMap")
      public String testMap(Map<String, Object> map) {
          map.put("testScope", "hello,Map");
          return "success";
      }
      
  • 实例

    • 定义user和product实体类;定义userDao和productDao类,将多个user和product放入字典和列表中,并暴露方法;定义userService和productService,对Dao暴露的方法进行封装

    • 定义LoginController

      @Controller
      public class LoginController {
          @Autowired
          private UserService userService;
          @RequestMapping("/user")
          public String sayHello() {
              return "user";
          }
          @RequestMapping("/login")
          public String login(User user, HttpServletRequest request) {
              User user2 = userService.getUserByUserName(user.getUserName());
              if (user2 != null && user2.getPassword().equals(user.getPassword())) {
                  HttpSession session = request.getSession();
                  session.setAttribute("loginUser", user2);
                  return "redirect:/getProductList";
              }
              request.setAttribute("msg", "账号或密码错误!");
              return "user";
          }
      }
      
    • 定义ProductController

      @Controller
      public class ProductController {
          @Autowired
          private ProductService productService;
          @RequestMapping("/getProductList")
          public ModelAndView getProductList() {
              ModelAndView modelAndView = new ModelAndView();
              modelAndView.setViewName("productList");
              List<Product> productList = productService.getProductList();
              modelAndView.addObject(productList);
              return modelAndView;
          }
          @RequestMapping("/getProduct")
          public String getProduct(Integer productId, Model model) {
              Product productById = productService.getProductById(productId);
              model.addAttribute("product", productById);
              return "product";
          }
      }
      

Spring MVC视图和视图解析器

  • 无论控制器方法的返回值是哪种类型,Spring MVC 内部最终都会将它们封装成一个 ModelAndView 对象
  • 仅仅是一个 String 类型的逻辑视图名(View Name)而已,例如“success”、“index”等。这种情况下,Spring MVC 就需要借助 ViewResolver(视图解析器)将 ModelAndView 对象中逻辑视图名解析为真正的 View 视图对象,然后才能响应给客户端展示
  • 需要在视图解析器中配置视图前缀和视图后缀,用来转化控制器返回的字符串

Spring MVC请求转发与重定向

  • 请求转发

    • 当控制器方法中所设置的逻辑视图名称以“forward:”为前缀时,该逻辑视图名称不会被 Spring MVC 配置的视图解析器解析,而是会将前缀“forward:”去掉,以剩余部分作为最终路径通过转发的方式实现跳转

    • 通过String类型的返回值实现转发

      @RequestMapping("/testDispatcher")
      public String testDispatcher() {
          return "forward:/login";
      }
      //即路径“/testDispatcher”请求最终会被转发到 “/login”上进行处理
      
    • 通过 ModelAndView 实现转发

      @RequestMapping("/testDispatcher")
      public ModelAndView testDispatcher() {
          ModelAndView modelAndView = new ModelAndView();
          //设置逻辑视图名
          modelAndView.setViewName("forward:/login");
          return modelAndView;
      }
      
  • 重定向

    • 当控制器方法中所设置的视图名称以“redirect:”为前缀时,该视图名称不会被 Spring MVC 配置的视图解析器解析,而是会将前缀“redirect:”去掉,以剩余部分作为最终路径通过重定向的方式实现跳转
    • 通过String类型的返回值实现转发
    • 通过 ModelAndView 实现转发
    • 重定向和转发的区别:转发不会改变导航栏里的url

Spring MVC实现RESTful

  • 通过 @RequestMapping +@PathVariable 注解的方式,来实现 RESTful 风格的请求

  • 通过@RequestMapping 注解的路径设置

    @RequestMapping("/testRest/{id}/{username}", method = RequestMethod.DELETE)
    
  • 通过 @PathVariable 注解绑定参数

    @RequestMapping("/testRest/{id}/{username}")
    public String testRest(@PathVariable("id") String id, @PathVariable("username")
            String username) {
        System.out.println("id:" + id + ",username:" + username);
        return "success";
    }
    

Spring MVC类型转化器

  • 作用是在控制器方法对请求进行处理前,先获取到请求发送过来的参数,并将其转换为控制器方法指定的数据类型,然后再将转换后的参数值传递给控制器方法的形参,这样后台的控制器方法就可以正确地获取请求中携带的参数了

  • Spring MVC 对于基本类型(例如 int、long、float、double、boolean 以及 char 等)已经做好了基本类型转换

  • 对于一些较为复杂类型的转换,例如 String 转换 Date 类型,以及开发人员自定义格式的数据的转换等,就需要我们根据自身的需求开发自定义类型转换器来转换

    /**
    * 自定义日期转换器
    */
    public class MyDateConverter implements Converter<String, Date> {
        private String datePatten = "yyyy-MM-dd";
        @Override
        public Date convert(String source) {
            System.out.println("前端页面传递过来的时间为:" + source);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePatten);
            try {
                return simpleDateFormat.parse(source);
            } catch (ParseException e) {
                throw new IllegalArgumentException("无效的日期格式,请使用正确的日期格式" + datePatten);
            }
        }
    }
    //还需要将其注册到Spring MVC的核心配置文件中,才能生效
    

Spring MVC格式化器

  • Spring 提供了一个 Formatter
    接口, T 表示目标数据类型,它被称为格式化转换器;特殊数据都要经过一定的格式化处理才能够正常使用

  • 同Converter的区别:Formatter 的源类型必须是 String 类型,而 Converter 的源类型可以是任意数据类型

  • 定义格式化器需要重写parse和print方法

  • 日期格式化

    • DateTimeFormat 注解可对 java.util.Date、java.util.Calendar、java.long.Long 等时间类型的数据进行标注

    • 控制器中:

      @DateTimeFormat(pattern = "yyyy-MM-dd")
      private Date date;
      
    • 模板中:

      <tr>
          <td>日期:</td>
          <td th:text="${#dates.format(market.getDate(),'yyyy-MM-dd')}"></td>
      </tr>
      
  • 数值格式化

    • @NumberFormat 注解可以用来格式化任何数字基本类型

    • 注解为货币类型

      @NumberFormat(style = NumberFormat.Style.CURRENCY)
      private BigDecimal money;
      

JSON数据交互

  • JSON转换注解

    image-20221115100808169

  • 实例

    • controller

      /**
      * 查看或回显商品信息,get:查看商品信息  update:为修改页回显的商品信息
      */
      @ResponseBody
      @RequestMapping("/product/{productId}")
      public Product getProduct(@PathVariable("productId") String productId) {
          Product product = productDao.getProductById(productId);
          return product;
      }
      /**
      * 新增商品
      *
      * @param product
      * @return
      */
      @ResponseBody
      @RequestMapping(value = "/product", method = RequestMethod.POST)
      public Product addProduct(@RequestBody Product product) {
          productDao.addProduct(product);
          return product;
      }
      
    • product_list.html

      • 主页面添加表格用来展示商品信息

        <tbody th:id="tb">
        
      • 通过ajax返回商品信息

        $(function () {
            $.ajax({
                //请求路径
                url: "http://localhost:8080/springmvc-json-demo/getProductList1",
                //请求类型
                type: "get",
                //定义发送请求的数据格式为JSON字符串
                contentType: "application/json;charset=utf-8",
                //定义回调响应的数据格式为JSON字符串,该属性可以省略
                dataType: "json",
                //成功响应的结果
                success: function (data) {
                    if (data != null) {
                        var html = "";
                        for (var i = 0; i < data.length; i++) {
                            var product = data[i];
                            html += "<tr>" +
                                "<td>" + product.productId + "</td>" +
                                "<td>" + product.productName + "</td>" +
                                "<td>" + product.price + "</td>" +
                                "<td>" + product.stock + "</td>" +
                                "<td><button  onclick='lookPage(" + product.productId + ")'>查看商品</button>" +
                                "<button  onclick='editPage(" + product.productId + ")';>修改商品</button>" +
                                "<button  onclick='deletePro(" + product.productId + ")';>删除商品</button></td>" +
                                "</tr>"
                        }
                        $("#tb").html(html);
                    }
                }
            });
        })
        
      • 首先通过css将增删查改的div块设置为不可见

        <style type="text/css">
            #addWindow, #editWindow {
                display: none;
                position: absolute;
                top: 25%;
                left: 25%;
                width: 30%;
                height: 40%;
                padding: 20px;
                border: 3px solid #ccc;
                background-color: white;
                z-index: 2;
                overflow: auto;
            }
        </style>
        
      • 每个商品信息栏后有增删查改,通过click方法,将addWindow/editWindow设置为可见

        $(document).ready(function () {
            //点击新增商品,弹出新增商品弹窗
            $("#btn").click(function () {
                $("#addWindow").slideDown(300);	 //slideDown方法以滑动方式显示被选元素
                $("#backGround").show();
            });
        
      • addWindow用来展示增加商品的页面

        <div id="addWindow">
            <label id="x" style="position: absolute;top:2px;left: 95%;font-size: 25px;">x</label>
            <h4>新增商品</h4>
            <form th:action="@{/product}" method="post">
                <table id="table-box" style="margin: auto">
                    <tr>
                        <td>商品 ID:</td>
                        <td><input type="text" id="productId" name="productId" required></td>
                    </tr>
                    <tr>
                        <td>商品名称:</td>
                        <td><input type="text" id="productName" name="productName" required></td>
                    </tr>
                    <tr>
                        <td colspan="2" align="center"><input id="addPro" type="submit" value="新增商品">
                            <input type="reset" id="reset" value="重置">
                        </td>
                    </tr>
                </table>
            </form>
        </div>
        <div id="backGround"></div>
        
      • 填完商品信息,点击提交后,通过jquery click调用add方法,向后端请求数据,返回的数据append到商品详情页

        $("#addPro").click(function () {
            add();
            $("#addWindow").slideUp(300);
            $("#backGround").hide();
            $("#reset").trigger("click")
        });
        
        $.ajax({
            //请求路径
            url: "http://localhost:8080/springmvc-json-demo/product",
            //请求类型
            type: "post",
            data: JSON.stringify({
                productId: productId,
                productName: productName,
            }), //定义发送请求的数据格式为JSON字符串
            contentType: "application/json;charset=utf-8",
            //定义回调响应的数据格式为JSON字符串,该属性可以省略
            dataType: "json",
            //成功响应的结果
            success: function (data) {
                if (data != null) {
                    var product = data;
                    var html = "<tr>" +
                        "<td>" + product.productId + "</td>" +
                        "<td>" + product.productName + "</td>" +
                        "<td><button onclick='lookPage(" + product.productId + ")'>查看商品</a>" +
                        "</tr>";
                    $("#tb").append(html);   
                }
            }
        

原文地址:http://www.cnblogs.com/z5onk0/p/16897643.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性