美文网首页
Spring MVC教程——检视阅读(二)

Spring MVC教程——检视阅读(二)

作者: 卡斯特梅的雨伞 | 来源:发表于2020-05-14 16:14 被阅读0次

Spring MVC Map集合参数封装

我们利用List集合来封装多个地址信息,其实把List集合换成Map集合也是可以的 。

示例:

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Spring MVC</title>
</head>
<body>
<h2>基本类型参数封装</h2>
<%--设置请求类型为post--%>
<form action="http://localhost:8080/hellospringmvc/say/helloParamMap" method="post">
    用户名:<input type="text" name="userName"><br>
    年龄:<input type="text" name="userAge"><br>
    <%--这里的address['a1'].city,a1是赋值给Map的key,city是赋值给Address的city属性--%>
    省份1:<input type="text" name="address['a1'].province"><br>
    城市1:<input type="text" name="address['a1'].city"><br>
    省份2:<input type="text" name="address['a2'].province"><br>
    城市2:<input type="text" name="address['a2'].city"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

注意:这里的address['a1'].city,a1是赋值给Map的key,city是赋值给Address的city属性 .

@RequestMapping(value ="/helloParamMap" ,method = RequestMethod.POST)
public String helloParamMap(User user) {
    System.out.println("用户名:" + user.getUserName());
    System.out.println("年龄:" + user.getUserAge());
    Map<String, Address> addressMap = user.getAddress();
    Set<Map.Entry<String, Address>> entries = addressMap.entrySet();
    for (Map.Entry<String, Address> entry : entries) {
        System.out.println(entry.getKey()+"--"+JSON.toJSONString(entry.getValue()));
    }
    return "success";
}
public class User {

    private String userName;

    private Integer userAge;

    private Map<String,Address> address;
       //......
    }
用户名:艾米
年龄:18
a1--{"city":"深圳","province":"粤"}
a2--{"city":"金门","province":"闽"}

Spring MVC 自定义类型转换

Spring MVC默认情况下可以对基本类型进行类型转换,例如可以将String转换为Integer,Double,Float等。但是Spring MVC并不能转换日期类型(java.util.Date),如果希望把字符串参数转换为日期类型,必须自定义类型转换器。接下来讲解如何自定义类型转换器。 可以加@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")进行处理。

import cn.vv.work.material.api.base.search.BaseSearch;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.List;

@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfoSearch extends BaseSearch implements Serializable {


    @ApiModelProperty(value = "购入日期起始")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime purchaseTimeStart;

    @ApiModelProperty(value = "购入日期结束")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime purchaseTimeEnd;
}

Spring MVC 使用Servlet API

在Spring MVC应用中,我们也经常需要使用到原生的Servlet API来满足功能的开发需求。接下来介绍如何在Spring MVC中使用Servlet 相关API。

实例:

@RequestMapping("/leap")
public void leap(HttpServletRequest request,
                   HttpServletResponse response,
                   HttpSession session)
        throws IOException {
    request.setAttribute("request","take leap of faith");
    session.setAttribute("session","take leap of faith");
    response.sendRedirect("/hellospringmvc/say/hello");
}

@RequestHeader注解

Spring MVC提供@RequestHeader注解方便我们获取请求头信息。

示例:

@RequestMapping(value ="/helloHeader")
public String helloHeader(@RequestHeader("host") String host, @RequestHeader("accept") String accept) {
    System.out.println("host---"+host);
    System.out.println("accept---"+accept);
    return "success";
}

输出:

host---localhost:8080
accept---text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

@CookieValue注解

Spring MVC提供@CookieValue方便我们获取指定Cookie数据。

示例:

@RequestMapping(value ="/helloCookie")
public String helloHeader(@CookieValue("JSESSIONID") String sessionId) {
    System.out.println("JSESSIONID---"+sessionId);
    return "success";
}

Spring MVC 静态资源访问

无法访问静态资源的原因

当Spring MVC配置的拦截路径为 / 或 / 的时候,我们项目会无法访问静态资源文件*,如:

springmvc.xml配置:

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

三种Spring MVC访问静态资源的方案

1、通过Tomcat的DefaultServlet配置访问静态资源。

在我们应用的web.xml重新配置DefaultServlet的映射路径,让其对特定的静态资源进行处理。

首先,我们要明白在Spring MVC应用之所以访问不了静态资源,是因为我们配置的DispathcerServlet映射路径覆盖了Tomcat的DefaultServlet的映射路径。

Tomcat的DefaultServlet配置,在Tomcat根目录的conf/web.xml

img img

实现方式,在项目的web.xml配置:

<!--重新配置Tomcat的DefaultServlet的映射路径-->
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
    <url-pattern>*.jpg</url-pattern>
    <url-pattern>*.css</url-pattern>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.png</url-pattern>
    <url-pattern>*.gif</url-pattern>
</servlet-mapping>
2、通过<mvc:resources/>标签,把页面的不同请求,转发到项目内部的某个目录下
Spring MVC提供了mvc:resources/标签,该标签的作用可以把页面的不同请求,转发到项目内部的某个目录下。该标签配置在hellospringmvc-servlet.xml文件下。
<!--静态资源处理-->
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>

mapping:代表映射页面的访问路径。

location:代表项目内的具体的物理路径地址。

3、通过<mvc:default-servlet-handler/>把所有静态资源目录的文件对外映射出去。
第二种方案的使用比较繁琐,因为需要一个个目录进行配置,其实有一个更加方便的标签:

mvc:default-servlet-handler/,该标签相当于一次帮助我们把所有静态资源目录的文件对外映射出去。该标签配置在hellospringmvc-servlet.xml文件下。 
  <!--静态资源处理-->
<mvc:default-servlet-handler/>

Model与ModelMap

Spring MVC应用中,我们经常需要在Controller将数据传递到JSP页面,除了可以通过HttpServletRequest域传递外,Spring MVC还提供了两个Api,分别为Model接口和ModelMap类。

Model与ModelMap的关系

Model接口和ModelMap类都有一个共同的子类:BindingAwareModelMap 。而BindingAwareModelMap底层其实是往HttpServletRequest域存入数据,所以Model接口或者ModelMap的底层也是往request域存入数据!

示例:

show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>show page</title>
</head>
<body>
<%--可以直接取也可以通过requestScope取值--%>
<%--获取Model数据-${requestScope.question}--%>
获取Model数据-${question}
<hr/>
获取ModelMap数据-${requestScope.answer}
</body>
</html>
@Controller
public class ModelController {

    @RequestMapping("/helloModel")
    public String helloModel(Model model){
        model.addAttribute("question","what do you want?");
        return "show";
    }

    @RequestMapping("/helloModelMap")
    public String helloModelMap(ModelMap modelMap){
        modelMap.addAttribute("answer","I want my phone call!");
        return "show";
    }
}

输出:

image.png
image.png

@ModelAttribute注解

@ModelAttribute作用

@ModelAttribute注解的作用,将请求参数绑定到Model对象。被@ModelAttribute注释的方法会在Controller每个方法执行前被执行(如果在一个Controller映射到多个URL时,要谨慎使用)。

@ModelAttribute注解的使用总结

@ModelAttribute使用位置

在SpringMVC的Controller中使用@ModelAttribute时,其位置包括下面三种:

  1. 应用在方法上
  2. 应用在方法的参数上
  3. 应用在方法上,并且方法同时使用@RequestMapping
1、应用在方法上
用在无返回值的方法

在model方法之前会执行setAttribute()方法。因此在setAttribute()方法中,请求传递的name参数存入Model对象,该参数值也会随着model方法带到JSP页面中。

实例:

result.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>@ModelAttribute注解的使用</title>
</head>
<body>
${name}
</body>
</html>
@Controller
public class ModelAttributeController {

    @ModelAttribute
    public void setAttribute(@RequestParam(value = "userName",required = false) String name, Model model){
        model.addAttribute("name",name);
    }

    @RequestMapping("/result")
    public String result(){
        return "result";
    }
}

请求:<http://localhost:8080/hellospringmvc/result?userName=艾米

用在带返回值的方法

带有返回值的情况,其实就是自动把方法返回值存入Model对象,@ModelAttribute的value属性就是Model的key。相当于

model.addAttribute("name",name);

示例:

@Controller
public class ModelAttributeController {

    @ModelAttribute("name")
    public String setAttribute(@RequestParam(value = "userName",required = false) String name){
        return name;
    }

    @RequestMapping("/result")
    public String result(){
        return "result";
    }
}
2、应用在方法的参数上

@ModelAttribute注解应用在方法的参数上,其实就是从Model对象中取出对应的属性值。

示例:

@Controller
public class ModelAttributeController {
    @ModelAttribute("name")
    public String setAttribute(@RequestParam(value = "userName",required = false) String name){
        return name;
    }

    @RequestMapping("/resultPara")
    public String resultPara(@ModelAttribute("name") String name){
        System.out.println("name="+name);
        return "result";
    }
}
方法上+@RequestMapping

@ModelAttribute和@RequestMapping同时应用在方法上的时候,有两层意义:

  1. 方法的返回值会存入Model对象中,key就是ModelAttribute的value属性值
  2. 方法的返回值不再是方法的访问路径,访问路径会变为@RequestMapping的value值,例如:@RequestMapping(value = "/model") 跳转的页面是model.jsp页面。

示例:这种使用方式请求的时候是通过其他方法调用进来的。

@RequestMapping("/result")
@ModelAttribute("name")
public String resultMapping(@RequestParam(value = "userName",required = false) String name){
    System.out.println("name="+name);
    return name;
}

@SessionAttributes注解

一般不用这个注解,范围太广,有其他代替方法,最简单的就是用个redis缓存。

@SessionAttributes作用

默认情况下Spring MVC将模型中的数据存储到request域中。当一个请求结束后,数据就失效了。如果要跨页面使用。那么需要使用到session。而@SessionAttributes注解就可以使得模型中的数据存储一份到session域中。

注意:@SessionAttributes注解只能用在类上!

@SessionAttributes属性:

  • name:代表取Model对象的对应属性,存入session域中
  • type:属性类型

示例:

@Controller
@SessionAttributes(names = "name",types = String.class)
public class SessionAttributeController {

    @RequestMapping("/showSession")
    public String showSession(Model model,String name){
        model.addAttribute("name",name);
        return "sessionResult";
    }
}

sessionResult.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>@SessionAttributes注解的使用</title>
</head>
<body>
request:${requestScope.name}<br/>
session:${sessionScope.name}<br/>
</body>
</html>

输出:

image.png

Spring MVC 控制器返回值

Spring MVC的控制器方法返回值可以支持多种写法,每种写法的场景和效果都不一样。下面分别来看看每种返回值的使用。

  1. 普通字符串
  2. 转发字符串
  3. 重定字符串
  4. void
  5. ModelAndView
  6. Java对象

普通字符串——jsp页面地址+页面名称

返回普通字符串这种情况比较常见,主要用在我们处理完业务逻辑后,需要跳转到应用的其他页面。

只能转发到视图解析器指定的特定目录。

/**
 * 1)字符串 - 普通字符串(代表页面名称,不是完整路径,最后经过视图解析器的解析)
 *    优势:写法简单
 *    劣势:只能转发到视图解析器指定的特定目录
 */
@RequestMapping("/hello")
public String sayHello() {
    return "success";
}

转发字符串

普通字符串,只能转发到视图解析器指定前缀的目录下的页面,如果想转发到视图解析器目录以外的页面,这时可以使用转发字符串的写法。

forward:完整页面的路径 。

示例:可以传递request域对象数据

/**
 * 2)字符串 - 转发字符串
 *     转发字符串格式:
 *        forward:完整页面的路径      例如:forward:/pages/index.jsp
 *
 *    优势:更加灵活,可以转到本项目下的任何页面,可以传递request域对象数据
 *    劣势:写法稍复杂
 */
@RequestMapping("/forward")
public String forward(){
    return "forward:/index.jsp";
}

重定向字符串

如果希望使用重定向的方式跳转页面,这时可以使用重定向字符串完成。

示例:不能转发reques域对象数据

/**
 * 3)字符串 - 重定向字符串
 *     重定向字符串格式:
 *        redirect:完整页面的路径      例如:redirect:/pages/index.jsp
 *
 *    优势:很灵活,可以重定向到项目内和项目以外的页面
 *    劣势:写法稍复杂,不能转发reques域对象数据
 */
@RequestMapping("/redirect")
public String redirect(){
    return "redirect:http://www.baidu.com";
}

返回空

一般我们在文件下载的时候,就不需要控制器方法返回任何内容,所以设置为void即可。

示例:

/**
 * 4)返回void
 * 用于文件下载
 */
@RequestMapping("/download")
public void download(HttpServletResponse response) {
    //模拟文件下载
    //1.读取需要下载的文件
    File file = new File("e:/car.jpg");

    //2.构建文件输入流
    try (InputStream in = new FileInputStream(file); OutputStream out = response.getOutputStream()) {
        //4.边读边写
        byte[] buf = new byte[1024];
        int len = 0;

        while ((len = in.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return;
}

ModelAndView

Spring MVC提供了ModelAndView对象,该对象既可以存储数据到request域,也可以设置视图。其实Spring MVC任何处理器适配器最终执行完控制器后,都会返回ModelAndView对象。所以这是一个比较底层的对象。

示例:

 @RequestMapping("/mv")
    public ModelAndView mv(){
        ModelAndView mv = new ModelAndView();
        //设置模型数据 值attributeValue可以是任何对象Object
        mv.addObject("name","池寒枫");
        //设置视图数据
        //设置viewName代表页面名称,不是完整路径,最后经过视图解析器的解析
        mv.setViewName("result");
        return mv;
    }

输出:

image.png

返回Java对象

这里返回的Java对象,可能是普通JavaBean,也可以是List或Map集合等。一般希望把控制器的返回Java对象转换为Json字符串,才需要返回Java对象。

Spring MVC JSON数据转换

场景:

在开发中后端经常需要接受来自于前端传递的Json字符串数据并把Json字符串转换为Java对象 。

后端也经常需要给前端把Java对象数据转换为Json字符串返回 。

办法:

使用@RequestBody和@ResponseBody注解。

Spring MVC默认是无法实现Json数据转换功能的,需要额外导入fastjson包来支持Json数据转换。

编写JsonController,这里用到两个关键注解@RequestBody@ResponseBody

  • @RequestBody:完成页面Json字符串转换为后端Java对象
  • @ResponseBody:完成后端Java对象转换为前端Json字符串

示例:

<!-- 平时处理json用的 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.29</version>
</dependency>
<!-- jackson支持包 -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.5</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.5</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.5</version>
</dependency>
@Controller
public class JsonController {

    @RequestMapping("/json")
    @ResponseBody
    public MercenaryUser showJson(@RequestBody MercenaryUser user){
        System.out.println("前端发送的数据:"+ JSON.toJSONString(user));
        //后台返回json字符串给前端
        user.setId(1);
        user.setName("艾米");
        user.setAge(20);
        user.setRide("冥牙");
        return user;
    }

    @RequestMapping("/toJson")
    public String toJson(){
        return "json";
    }
}

json.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSON格式转换</title>
    <%--使用jQuery实现ajax异步请求后端Controller,同时发送Json字符串对象--%>
    <%--<script src="/hellospringmvc/js/jquery-1.7.1.min.js"></script>--%>
    <%--CDN--%>
    <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
</head>
<body>
<script>
    //页面加载完毕
    $(function () {
        //点击按钮,发送post请求,传递json参数
        $("#btn").click(function () {
            $.ajax({
                //设置请求类型
                type: 'post',
                //请求路径
                url: 'http://localhost:8080/hellospringmvc/json',
                //传递json参数
                data: '{"id":3,"name":"池傲天","age":21,"ride":"DeathDragon"}',
                //指定参数类型(如果json参数格式,必须设置为json类型)
                contentType: 'application/json;charset=utf-8',
                //该方法接收后台返回的数据格式
                dataType: 'json',
                //处理方法
                success: function (result) {
                    alert(result.id + '--' + result.name + '--' + result.age + '--' + result.ride);
                }

            });
        });
    });

</script>

<input type="button" value="Json字符串与Java对象转换" id="btn">
</body>
</html>
public class MercenaryUser {

    private Integer id;
    private String name;
    private Integer age;
    private String ride;
    //...
    }

hellospringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 1.扫描Controller的包-->
    <context:component-scan base-package="com.self" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 4.配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 4.1 页面前缀 -->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!-- 4.2 页面后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 3.开启mvc注解驱动-->
    <!-- 3.创建处理器适配器和处理器映射器-->
    <!--在Spring中一般采用@RequestMapping注解来完成映射关系,
    要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,
    这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助我们自动完成上述两个实例的注入。
    -->
    <mvc:annotation-driven/>

    <!--静态资源处理-->
    <!--该标签相当于一次帮助我们把所有静态资源目录的文件对外映射出去。-->
    <mvc:default-servlet-handler/>
</beans>

输出:

前端发送的数据:{"age":21,"id":3,"name":"池傲天","ride":"DeathDragon"}
image.png

报错

1、jquery方法执行不了。json请求页面无响应。

A:首先要引入jquery-1.7.1.min.js 文件,放到项目目录上,并通过从项目名开始的路径引用,或者全路径,从主机路径开始,否则会找不到js文件,因为我们没有设置相对路径。
<%--使用jQuery实现ajax异步请求后端Controller,同时发送Json字符串对象--%>
    <script src="/hellospringmvc/js/jquery-1.7.1.min.js"></script>

2、发起ajax请求时415报错——不支持的媒体类型(Unsupported media type)

jquery-1.7.1.min.js:2660 POST http://localhost:8080/hellospringmvc/json 415 ()

A:我们需要: 一:在hellospringmvc-servlet.xml中配置开启mvc注解驱动,该配置会创建处理器适配器和处理器映射器,自动注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean。
AnnotationMethodHandlerAdapter将会初始化7个转换器,可以通过调用AnnotationMethodHandlerAdapter的getMessageConverts()方法来获取转换器的一个集合 List<HttpMessageConverter>。
ByteArrayHttpMessageConverter 
StringHttpMessageConverter 
ResourceHttpMessageConverter 
SourceHttpMessageConverter 
XmlAwareFormHttpMessageConverter 
Jaxb2RootElementHttpMessageConverter 
MappingJacksonHttpMessageConverter
对于json的解析就是通过MappingJacksonHttpMessageConverter转换器完成的。
二:依赖jackson包,这样才能通过转换器+jackson解析json数据,@RequestBody需要。
    <!-- jackson支持包 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.5</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.5</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.5</version>
    </dependency>

如果还是报415错误,那可能是因为在hellospringmvc-servlet.xml显式配置的处理器和适配器,导致转换器没有初始化出来。要注释掉。如下:

<!--2.创建RequestMappingHandlerMapping-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->

<!--3.创建RequestMappingHandlerAdapter-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->

参考:使用@RequestBody注解处理json时,报出HTTP Status 415的解决方案

注意:在hellospringmvc-servlet.xml配置中,当我们配置了静态资源处理时,就一定要开启mvc注解驱动,否则我们请求的处理都会被静态资源处理器处理了,导致请求的页面报404请求资源不存在。因此在hellospringmvc-servlet.xml配置中,两个都是一定要配置的,缺一不可。

<!-- 3.开启mvc注解驱动-->
    <!-- 3.创建处理器适配器和处理器映射器-->
    <!--在Spring中一般采用@RequestMapping注解来完成映射关系,
    要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,
    这两个实例分别在类级别和方法级别处理。而<mvc:annotation-driven/>配置帮助我们自动完成上述两个实例的注入。
    -->
    <mvc:annotation-driven/>

    <!--静态资源处理-->
    <!--该标签相当于一次帮助我们把所有静态资源目录的文件对外映射出去。-->
    <mvc:default-servlet-handler/>
image.png

Spring MVC RESTful风格开发

什么是RESTful风格?

RESTful,也叫REST(英文: Representational State Transfer, 简称 REST描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种 Web 服务交互方案中,REST 相比于SOAP(Simple Object Access protocol, 简单对象访问协议) 以及 XML-RPC 更加简单明了, 无论是对 URL 的处理还是对 Payload 的编码, REST 都倾向于用更加简单轻量的方法设计和实现。 值得注意的是 REST 并没有一个明确的标准, 而更像是一种设计的风格。REST 其核心价值在于如何设计出符合 REST 风格的网络接口。 基于这个风格设计的软件可以更简洁, 更有层次, 更易于实现缓存等机制。

简单地说:使用RESTful风格可以让我们客户端与服务端访问的URL更加简洁方便!

以下给出两个例子,前者没有采用RESTful风格,后者采用RESTful风格。

没有采用RESTful风格的URL

采用RESTful风格的URL

对比发现,RESTful风格更加简洁,RESTful主要依靠不同的请求方法来区分不同操作类型,这个与传统URL最大的区别。

Spring MVC开发RESTful应用

前置条件

为了在前端模拟出不同的请求方式,需要在web.xml引入SpringMVC提供的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>

restful.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Spring MVC进行RESTful风格开发</title>
</head>
<body>

<!--增加 -->
<form action="/hellospringmvc/rest" method="post">
    <input type="submit" value="增加">
</form>

<!--查询 -->
<form action="/hellospringmvc/rest" method="get">
    <input type="submit" value="查询">
</form>

<!--修改 -->
<form action="/hellospringmvc/rest/8" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="修改">
</form>

<!--删除 -->
<form action="/hellospringmvc/rest/9" method="post">
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="删除">
</form>
</body>
</html>
@Controller
@RequestMapping("/rest")
public class RestfulController {

    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public String save() {
        System.out.println("增加...");
        return "success";
    }

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String get() {
        System.out.println("查询...");
        return "success";
    }

 /*   @RequestMapping(value = "/{id}",method = RequestMethod.POST)
    @ResponseBody
    public String update(@PathVariable("id") Integer id){
        System.out.println("修改...id="+id);
        return "success";
    }*/

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    @ResponseBody
    public String update(@PathVariable("id") Integer id) {
        System.out.println("修改...id=" + id);
        return "success";
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable("id") Integer id) {
        System.out.println("删除...id=" + id);
        return "success";
    }
}

注意点:

  1. 为了接收RESTful请求,使用method属性指定对应的请求方式
  2. 使用@PathVariable注解接收RESTful请求的参数
  3. RESTful风格的请求处理完毕后,通常@ResponseBody注解把数据转换为Json返回,尽量不要转发或重定向页面,因为页面不支持PUT和DELETE请求。

请求:http://localhost:8080/hellospringmvc/restful.jsp

输出:

增加...
查询...
修改...id=8
删除...id=9
image.png

报错:如果不配置转换请求方式的过滤器HiddenHttpMethodFilter,请求会报错。

image.png

Spring MVC 文件上传

文件上传是表现层常见的需求,在Spring MVC中底层使用Apache的Commons FileUpload工具来完成文件上传,对其进行封装,让开发者使用起来更加方便。

文件上传需要:

  • 导入common-fileupload包
  • 配置文件解析器
注意:
  1. 必须配置CommonsMultipartResolver解析器
  2. 该解析器的id必须叫multipartResolver,否则无法成功接收文件
  3. 可以通过maxUploadSize属性限制文件上传大小
上传表单注意:
  1. 表单的enctype必须改为multipart/form-data
  2. 表单提交方式必须为POST,不能是GET

注意:

这里使用MultipartFile对象接收文件,并把文件存放在项目的upload目录下,同时还接收了普通参数。

示例:

pom.xml

<!-- commons-fileUpload -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>

hellospringmvc-servlet.xml

<!-- 配置文件上传解析器 注意:必须配置id,且名称必须为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 配置限制文件上传大小 (字节为单位)-->
    <property name="maxUploadSize" value="1024000"/>
</bean>

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Hello Spring MVP</title>
</head>
<body>
<h1>上传成功!</h1>
</body>
</html>

upload.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
<h3>SpringMVC方式文件上传</h3>
<form action="/hellospringmvc/upload" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="fileName"> <br/>
    文件描述:<input type="text" name="desc"> <br/>
    <input type="submit" value="上传">
</form>
</body>
</html>
@Controller
public class UploadController {

    @RequestMapping("/upload")
    public String upload(HttpServletRequest request, MultipartFile fileName, String desc) {
        //1.获取网站的upload目录的路径: ServletContext对象
        //F:\self\hellospringmvc\target\hellospringmvc-1.0-SNAPSHOT\upload
        String upload = request.getSession().getServletContext().getRealPath("upload");
        ///F:/self/hellospringmvc/target/hellospringmvc-1.0-SNAPSHOT/WEB-INF/classes//upload
        String upload2 = UploadController.class.getResource("/").getFile()+"/upload";
        //判断该目录是否存在,不存在,自己创建
        File file = new File(upload);
        if (!file.exists()) {
            file.mkdir();
        }
        //把文件保存到upload目录
        //2.1 原来的文件名
        String originalFilename = fileName.getOriginalFilename();
        //2.生成随机文件名称
        String uuId = UUID.randomUUID().toString();
        //2.3 获取文件后缀 如 .jpg
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        //2.4 最终的文件名
        String newName = uuId + suffix;
        //3.保存
        try {
            //目标文件传入地址路径+名称
            fileName.transferTo(new File(upload + "/" + newName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件描述:" + desc);
        //跳转到上传成功页面
        return "success";
    }
}

请求:http://localhost:8080/hellospringmvc/upload.jsp

输出:上传成功。

image.png

相关文章

网友评论

      本文标题:Spring MVC教程——检视阅读(二)

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