硬核!springmvc全面详解,包含各种核心知识点!

已同步微信公众号乐享Coding,获取更多Java学习资源,技术交流群
期待你的关注!

SpringMVC总结整理

web开发底层是servlet,框架是在servlet基础上面加一些功能,方便web开发。

SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品。它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时还支持Restful编程风格的请求。

将应用程序分为Controller,Model,View三层,Controller接收用户请求,调用Model生成业务数据,传递给View。

核心组件

前端控制器(DispatcherServlet)
  • **【总指挥】**负责接收用户的提交的所有请求,如传统的jsp文件,调用其他的控制器Controller对象,并把请求处理的结果显示给用户。

    // web.xml文件中配置
    
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
        <!--配置DispatchServlet,MVC核心,前端控器器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring_mvc.xml</param-value> <!-- classpath:指resource根目录 -->
        </init-param>
        <!-- 启动顺序,数字越小,启动越早 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern> <!-- 拦截所有请求 -->
    </servlet-mapping>
</web-app>
处理器(Handler)
  • 完成具体的业务逻辑,相当于servlet或action。

    // 就是一个方法
    
请求到处理器映射(HandlerMapping)
  • DispatcherServlet接收到请求之后,通过HandlerMapping将不同的请求映射到不同的请求映射到不同的Handler。

    // @RequestMapping注解将URL请求与业务方法(Handler)映射
    
处理器适配器(HandlerAdapter)
  • Handler执行业务方法之前,需要进行一系列的操作,如表单数据的验证,数据类型的转换,将表单数据封装成JavaBean等,因此开发者只需将注意力集中到业务逻辑的处理上,DispatcherServlet通过HandlerAdapter执行不同的Handler。
视图解析器(ViewResolver)
  • DispatcherServlet通过它将逻辑视图转换为物理视图,最终将渲染结果响应给客户端。

    // resource文件夹下spring_mvc.xml配置视图解析器
    
<!--xml视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀 value属性指的是web文件夹的根目录-->
        <property name="prefix" value="/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
处理器拦截器(HandlerInterceptor)
  • 是一个接口,如果需要完成拦截处理,实现该接口。
处理器执行链(HandlerExecutionChain)
  • 处理器执行链,包含两部分,HandlerInterceptor和Handler
ModelAndView

装载了模型数据和视图信息,作为Handler的处理结果(业务方法返回ModelAndView对象),之后返回给DispatcherServlet做下一步处理。

工作流程

  1. 客户端请求被DispatcherServlet接收。
  2. 根据HandlerMapping映射到Handler。
  3. 生成Handler和HandlerInterceptor。
  4. Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet。
  5. DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理。
  6. Handler返回一个ModerAndView对象给DispatcherServlet。
  7. DispatcherServlet将获取的ModerAndView对象传给ViewResolver视图解析,将逻辑视图解析为物理视图View。
  8. ViewResolver返回一个View给DispatcherServlet。
  9. DispatcherServlet根据View进行视图渲染(将模型数据Model填充到视图View中)
  10. DispatcherServlet将渲染后的结果响应给客户端。

实际开发

流程非常复杂,实际开发中使用极其简单,因为大部分的组件不需要开发者创建,管理,只需要通过配置文件的方式完成配置即可,真正需要开发者进行处理的只有Handler,View。

Tomcat运行配置

打war包
  • IDEA中按快捷键ctrl+alt+shift+s打开project Structure

  • 之后在tomcat中配置war包启动

注意

每次pom.xml中导入新的依赖,需要看war包中是否也导入成功了,有时会没有导入就手动添加上。

中文乱码问题

前端发起请求后端收到却包含中文乱码
  • 解决办法,只需在web.xml配置SpringMVC自带的过滤器即可。
<!--配置SpringMVC自带的过滤器解决乱码问题-->
    <filter>
        <filter-name>encodingFilter</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>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
后端响应前端JSON数据时乱码
  • 解决办法,spring_mvc.xml配置消息转换器
<mvc:annotation-driven conversion-service="conversionService">
	<mvc:message-converters register-defaults="true">
	    <!--配置消息转换器,解决后台响应数据时中文乱码-->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
        </bean>
	</mvc:message-converters>
</mvc:annotation-driven>

注解

【@RequestMapping】

将URL请求与业务方法进行映射,在Handler的类定义处以及方法定义处都可以添加@RequestMapping。

相关参数

  1. value:指定URL请求的实际地址,是@RequestMapping的默认值。

    @RequestMapping(value = "/index") 
    
    @RequestMapping("/index") 
    
  2. method:指定请求的method类型,GET,POST,PUT,DELET

    @RequestMapping(value = "/index",method = RequestMethod.GET)
    

    表示只能接受GET请求。

  3. params:指定请求中必须包含某些参数,否则无法调用该方法。

    @RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id"= 1 })
    

    该代码表示请求中必须包含name和id两个参数,同时id的值必须是1。

    方法中可以传递请求中接收的参数,分两种情况

    假设是index方法

    • 请求参数与形参名称相同

      @RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id"= 1 })
      public String index(String name,int id)
      {
          System.out.println(name+id);
          return "index";
      }
      
    • 请求参数与形参名称不相同【需要加@RequestParam注解进行参数绑定】

      @RequestMapping(value = "/index", method = RequestMethod.GET, params = {"name", "id"= 1 })
      public String index(@RequestParam("name") String str,@RequestParam("id") int sid)
      {
          System.out.println(name+id);
          return "index";
      }
      

      该代码表示将请求的参数name和id分别赋值给了形参str和sid,同时完成了数据类型的转换,将字符串类型“1”转换为了int类型1,再赋给sid,这些工作都是由HandlerAdapter来完成的。

    Restful风格的URL

    • 传统类型传递参数 http://localhost:8080/index?name=xiaole&id=1

    • Restful传递参数 http://localhost:8080/index/xiaole/1

      @RequestMapping("/restful/{name}/{id}")
      public String restful(@PathVariable("name") String name,@PathVariable("id") int sid)
      {
          System.out.println(name+id);
          return "index";
      }
      

      Tips:无论请求参数名和业务方法中形参是否相同,都需要加@PathVariable注解进行映射

      • 映射 Cookie

        • Spring MVC通过映射可以直接在业务方法中获取Cookie的值。

          @RequestMapping("/cookie")
          public String cookie(@CookieValue(value = "JSESSIONID") String sessionId)
          {
              System.out.println(sessionId);
              return "index";
          }
          
      • 使用JavaBean绑定参数

        • Spring MVC 会根据请求参数名和JavaBean属性名进行自动匹配,自动为对象填充属性值,同时支持级联属性(对象中包含对象的属性)

          • 实体类 User 和 Address(文件夹Entity)
          @Data //必须加,否则接收不到
          public class User {
              private Integer id;
              private String name;
              private Address address; //级联属性
          }
          
          @Data
          public class Address {
              private String value;
          }
          
          • JSP文件的前端表单
          <form action="/hello/save" method="post">
              用户id :<input type="text" name="id"><br>
              用户名: <input type="text" name="name"><br>
              地址: <input type="text" name="address.value"><br> <%--级联属性--%>html
              <input type="submit" value="注册">
          </form>
          
          • Controller包下的handler类业务方法
          @RequestMapping(value = "/hello/save", method = RequestMethod.POST)
          public String save(User user) {
              System.out.println(user);
              return "index";
          }
          
          @RequestMapping("/hello")
          public String submit() {
              return "register";
          }
          

          测试地址:http://localhost:8080/hello

          Tips:需要配置解决乱码(过滤器)

      • html页面进行转发和重定向
        • 【转发】默认

          return "forward:/index";  ==  return "index";
          
        • 【重定向】

          return "redirect:/index";
          
【@Controller】

在类定义处添加,将该类交给IOC容器来管理(结合springmvc.xml的自动扫描配置使用),同时使其成为一个控制器,使得每一个业务方法的返回值都会交给视图解析器进行解析。

【@Requestbody】

不进行视图解析

在类定义处添加,也可以单独在方法中添加,表示直接将业务方法的返回值响应给客户端,不加的话返回的话,会将返回值传递给DispatcherServlet,再由DispatcherServlet调用ViewResolver对值进行解析,映射到一个jsp资源或html资源。

【@RestController】

@Requestbody+@Controller,在类定义处添加,包含两个注解的功能,即其类下的所有业务方法都不进行解析视图。

数据绑定

在后端的业务方法中直接获取客户端HTTP请求中的参数,将请求的参数映射到业务方法的形参中,Spring MVC中数据绑定的工作是由HandlerAdapter来完成的。

【基本数据类型】
  • @ResponseBody //直接将业务方法的返回值响应给客户端,不需要视图解析
    public String base(int id) {}; //业务方法中传基本数据类型int
    
【包装类】
  • 建议使用,因为可以接收null值,当HTTP请求没有参数时,不会抛出异常,基本数据类型不行。

    @ResponseBody //直接将业务方法的返回值响应给客户端,不需要视图解析
    public String pack(Integer id) {}; //业务方法中传包装类Integer
    
    public String pack(@RequestParam(value = "num",required = false,defaultValue = "10") Integer id) {}; //也可以加@RequestParam注解,required属性是必须加或否,范围布尔值,false情况下可设默认值
    
【集合】
  • 创建userList实体类
@Data
public class userList {
    private List<User> userList;
}
  • JSP前端页面
<!--List.jsp页面-->
<form action="/list" method="post">
    用户1id :<input type="text" name="userList[0].id"><br>
    用户1名: <input type="text" name="userList[0].name"><br>
    1地址: <input type="text" name="userList[0].address.value"><br> <%--级联属性--%>
    用户2id :<input type="text" name="userList[1].id"><br>
    用户2名: <input type="text" name="userList[1].name"><br>
    2地址: <input type="text" name="userList[1].address.value"><br> <%--级联属性--%>
    <input type="submit" value="注册">
</form>
  • 业务方法
@RequestMapping("/list")
@ResponseBody
public String submitList(userList userList) {
    StringBuffer str= new StringBuffer(); //解决+号影响效率
    for (User user:userList.getUserList()
         ) {
        str.append(user);
    }
    return str.toString();
}

测试地址:http://localhost:8080/List.jsp

【Map】
  • 创建UserMap实体类
@Data
public class UserMap {
    private Map<String,User> userMap;
}
  • 业务方法
@RequestMapping(value = "/map", method = RequestMethod.POST)
@ResponseBody
public String submitMap(UserMap userMap) {
    StringBuffer str = new StringBuffer();
    for (String key : userMap.getUserMap().keySet()) {
        str.append(userMap.getUserMap().get(key)); //根据key找到value
    }
    return str.toString();
}
  • JSP前端页面
<!--Map.jsp页面-->
<form action="/map" method="post">
    用户1id :<input type="text" name="userMap['1'].id"><br>
    用户1名: <input type="text" name="userMap['1'].name"><br>
    1地址: <input type="text" name="userMap['1'].address.value"><br> <%--级联属性--%>
    用户2id :<input type="text" name="userMap['2'].id"><br>
    用户2名: <input type="text" name="userMap['2'].name"><br>
    2地址: <input type="text" name="userMap['2'].address.value"><br> <%--级联属性--%>
    <input type="submit" value="注册">
</form>

测试地址:http://localhost:8080/Map.jsp

【JSON数据】
  • 引入jquery静态文件,需要注意,js文件不需要被DispatcherServlet处理,因此在web.xml中配置静态文件过滤。
<!--静态js文件不被DispatcherServlet拦截处理-->
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>
  • 通过Ajax异步向后台传递JSON数据,前端代码:
<!--json.jsp页面-->
<script type="text/javascript">
    $(function () {
        var User = {
            "id": 1,
            "name": "寒风"
        }
        $.ajax({
            url: "/json",
            data: JSON.stringify(User),
            type: "POST",
            contentType: "application/json;charset=UTF-8",
            dataType: "JSON",
            success: function (data) {
                alert(data.id + "____" + data.name);
            }
        })
    })
</script>
  • 后端业务方法

    还需要考虑到前端JSON数据传来需要阿里工具包fastjson在后端转换为JavaBean!

    • pom.xml导入fastjson依赖
    <!--前端JSON数据转换成JavaBean-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
    
    • spring_mvc.xml进行配置fastjson
    <!--springMVC配置fastjson-->
     <mvc:annotation-driven>
            <mvc:message-converters register-defaults="true">
                <bean id="fastJsonHttpMessageConverter"
                      class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                    <!-- 加入支持的媒体类型:返回contentType-->
                    <property name="supportedMediaTypes">
                        <list>
                            <!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
                            <value>text/html;charset=UTF-8</value>
                            <value>application/json;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </mvc:message-converters>
        </mvc:annotation-driven>
    
@RequestMapping(value = "/json", method = RequestMethod.POST)
@ResponseBody
public User submitJson(@RequestBody User user) { //@RequestBody 接收前端Json数据
    System.out.println(user);
    user.setId(56);
    user.setName("小红");
    return user;
}

测试地址:http://localhost:8080/json.jsp

可能出现两个问题

  • springMVC版本太高不兼容,这里推荐

    <version>5.2.6.RELEASE</version>
    
  • fastjson的jar包为打进war包,需要手动导入。

自定义数据转换器

数据转换器是指将客户端 HTTP 请求中的参数转换为业务方法中定义的形参,自定义表示开发者可以自主设计转换的方式,HandlerApdter 已经提供了通用的转换,String 转 int,String 转 double,表单数据的封装等,但是在特殊的业务场景下,HandlerAdapter 无法进行转换,就需要开发者自定义转换器。

概括:前端请求参数 ( 映射–>) 业务方法中的形参 ,参数的数据类型也可能需要转换。

举例

Date类型与String类型的转换

  • 创建 DateConverter 转换器,实现 Conveter 接口。
public class DateConverter implements Converter<String, Date> {

private String pattern;

public DateConverter(String pattern){
    this.pattern = pattern;
}

@Override
public Date convert(String s) {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.pattern);
    Date date = null;
    try {
        date = simpleDateFormat.parse(s);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return date;
}
}
  • springmvc.xml 配置转换器。
<!-- 配置自定义转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
    <list>
        <bean class="com.Long.Converter.DateConverter">
            <constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
        </bean>
    </list>
</property>
</bean>

<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters register-defaults="true">
    <!--配置消息转换器,解决后台响应数据时中文乱码-->
    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
        <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
    </bean>
    <!--springMVC配置fastjson-->
    <bean id="fastJsonHttpMessageConverter"
          class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
        <!-- 加入支持的媒体类型:返回contentType-->
        <property name="supportedMediaTypes">
            <list>
                <!-- 这里顺序不能反,一定先写text/html,不然ie下会出现下载提示 -->
                <value>text/html;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>
</mvc:message-converters>
</mvc:annotation-driven>
  • JSP表单页面
<form action="/converter/date" method="post">
请输入日期:<input type="text" name="date"/>(yyyy-MM-dd)<br/>
<input type="submit" value="提交"/>
</form>
  • Handler(业务方法)
@RestController
@RequestMapping("/converter")
public class ConverterHandler {

@RequestMapping("/date")
public String date(Date date){
    return date.toString();
}
}

测试地址http://localhost:8080/date.jsp

模型数据解析

JSP 四大作用域对应的内置对象:pageContextrequestsessionapplication

模型数据的绑定是由 ViewResolver 来完成的,实际开发中,我们需要先添加模型数据(model),再交给 ViewResolver 来绑定(View)。

Spring MVC 提供了以下几种方式添加模型数据:

  • 【Map】
  • 【Model】
  • 【ModelAndView】
  • 【@SessionAttribute】
  • 【@ModelAttribute】
绑定到request 对象

JSP页面

<%--view.jsp页面--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>  <%--不忽略el表达式--%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${requestScope.user}
</body>
</html>
1、Map
//通过map将数据传到request域对象里面
@RequestMapping("/map")
public String map(Map<String,User> map){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    map.put("user",user);
    return "view";
}

测试地址http://localhost:8080/map

// User(id=1, name=寒风, address=null)
2、Model
//通过model将数据传到request域对象里面
@RequestMapping("/model")
public String model(Model model){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    model.addAttribute("user",user);
    return "view";
}

测试地址http://localhost:8080/model

// User(id=1, name=寒风, address=null)
3、ModelAndView
//通过ModelAndView将数据传到request域对象里面
@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
   User user = new User();
    user.setId(1);
    user.setName("寒风");
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("user",user);
    modelAndView.setViewName("view");
    return modelAndView;
}

@RequestMapping("/modelAndView2")
public ModelAndView modelAndView2(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("user",user);
    View view = new InternalResourceView("/view.jsp");
    modelAndView.setView(view);
    return modelAndView;
}

@RequestMapping("/modelAndView3")
public ModelAndView modelAndView3(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    ModelAndView modelAndView = new ModelAndView("view");
    modelAndView.addObject("user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView4")
public ModelAndView modelAndView4(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    View view = new InternalResourceView("/view.jsp");
    ModelAndView modelAndView = new ModelAndView(view);
    modelAndView.addObject("user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView5")
public ModelAndView modelAndView5(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    Map<String,User> map = new HashMap<>();
    map.put("user",user);
    ModelAndView modelAndView = new ModelAndView("view",map);
    return modelAndView;
}

@RequestMapping("/modelAndView6")
public ModelAndView modelAndView6(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    Map<String,User> map = new HashMap<String,User>();
    map.put("user",user);
    View view = new InternalResourceView("/view.jsp");
    ModelAndView modelAndView = new ModelAndView(view,map);
    return modelAndView;
}

@RequestMapping("/modelAndView7")
public ModelAndView modelAndView7(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    ModelAndView modelAndView = new ModelAndView("view","user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView8")
public ModelAndView modelAndView8(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    View view = new InternalResourceView("/view.jsp");
    ModelAndView modelAndView = new ModelAndView(view,"user",user);
    return modelAndView;
}

测试地址http://localhost:8080/modelAndView

4、HttpServletRequest
@RequestMapping("/request")
public String request(HttpServletRequest request){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    request.setAttribute("user",user);
    return "view";
}
5、@ModelAttribute
  • 定义一个方法,该方法专门用来返回要填充到模型数据中的对象。
@ModelAttribute
public User getUser(){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    return user;
}
@ModelAttribute
public void getUser(Map<String,User> map){
   User user = new User();
    user.setId(1);
    user.setName("寒风");
    map.put("user",user);
}
@ModelAttribute
public void getUser(Model model){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    model.addAttribute("user",user);
}
  • 业务方法中无需再处理模型数据,只需返回视图即可。
@RequestMapping("/modelAttribute")
public String modelAttribute(){
    return "view";
}
绑定到 session 对象
1、原生的 Servlet API
@RequestMapping("/session")
public String session(HttpServletRequest request){
    HttpSession session = request.getSession();
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    session.setAttribute("user",user);
    return "view";
}

@RequestMapping("/session2")
public String session2(HttpSession session){
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    session.setAttribute("user",user);
    return "view";
}
2、@SessionAttribute
@SessionAttributes(value = {"user","address"})
public class ViewHandler {
}

对于 ViewHandler 中的所有业务方法,只要向 request 中添加了 key = “user”、key = “address” 的对象时,Spring MVC 会自动将该数据添加到 session 中,保存 key 不变。

@SessionAttributes(types = {User.class,Address.class})
public class ViewHandler {
}

对于 ViewHandler 中的所有业务方法,只要向 request 中添加了数据类型是 User 、Address 的对象时,Spring MVC 会自动将该数据添加到 session 中,保存 key 不变。

绑定到 application 对象
@RequestMapping("/application")
public String application(HttpServletRequest request){
    ServletContext application = request.getServletContext();
    User user = new User();
    user.setId(1);
    user.setName("寒风");
    application.setAttribute("user",user);
    return "view";
}

REST

REST:Representational State Transfer,资源表现层状态转换,是目前比较主流的一种互联网软件架构,它结构清晰、标准规范、易于理解、便于扩展。

  • 资源(Resource)

网络上的一个实体,或者说网络中存在的一个具体信息,一段文本、一张图片、一首歌曲、一段视频等等,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每个资源都有对应的一个特定的 URI,要获取该资源时,只需要访问对应的 URI 即可。

  • 表现层(Representation)

资源具体呈现出来的形式,比如文本可以用 txt 格式表示,也可以用 HTML、XML、JSON等格式来表示。

  • 状态转换(State Transfer)

客户端如果希望操作服务器中的某个资源,就需要通过某种方式让服务端发生状态转换,而这种转换是建立在表现层之上的,所以叫做"表现层状态转换"。

特点
  • URL 更加简洁。
  • 有利于不同系统之间的资源共享,只需要遵守一定的规范,不需要进行其他配置即可实现资源共享。
如何使用

REST 具体操作就是 HTTP 协议中四个表示操作方式的动词分别对应 CRUD 基本操作。

GET 用来表示获取资源。

POST 用来表示新建资源。

PUT 用来表示修改资源。

DELETE 用来表示删除资源。

Handler业务方法(增删改查)

@RestController
@RequestMapping("/rest")
public class RestfulHandler {

    @Autowired
    private StudentRepository studentRepository;
    
	//查 发送get请求
    @GetMapping("/findAll")
    public Collection<Student> findAll(HttpServletResponse response){
        response.setContentType("text/json;charset=UTF-8");
        return studentRepository.findAll();
    }

    @GetMapping("/findById/{id}")
    public Student findById(@PathVariable("id") Integer id){
        return studentRepository.findById(id);
    }

    //增 发送post请求
    @PostMapping("/save")
    public void save(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }
	
    //改 发送put请求
    @PutMapping("/update")
    public void update(@RequestBody Student student){
        studentRepository.saveOrUpdate(student);
    }

    //删 发送delete请求
    @DeleteMapping("/deleteById/{id}")
    public void deleteById(@PathVariable("id") Integer id){
        studentRepository.deleteById(id);
    }
}

模拟Service层接口

public interface StudentRepository {
    Collection<Student> findAll();
    Student findById(Integer id);
    void saveOrUpdate(Student student);
    void deleteById(Integer id);
}

Service层实现类+模拟数据库(Dao层)

@Repository //交给IOC容器
public class StudentRepositoryImpl implements StudentRepository {
    private static Map<Integer, Student> studentMap;

    static {
        studentMap = new HashMap<Integer, Student>();
        studentMap.put(1, new Student(1, "小寒", 22));
        studentMap.put(2, new Student(2, "小肖", 18));
        studentMap.put(3, new Student(3, "小乐", 18));
    }

    @Override
    public Collection<Student> findAll() {
        return studentMap.values();
    }

    @Override
    public Student findById(Integer id) {
        return studentMap.get(id);
    }

    @Override
    public void saveOrUpdate(Student student) {
        studentMap.put(student.getId(), student);
    }

    @Override
    public void deleteById(Integer id) {
        studentMap.remove(id);
    }
}

实体类Student

@Data
@AllArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Integer age;
}

测试地址: http://localhost:8080/rest/findAll (查) 注:增删改用Postman

文件上传下载

单文件上传

底层是使用 Apache fileupload 组件完成上传,Spring MVC 对这种方式进行了封装。

  • pom.xml导入commons-io和commons-fileupload的jar包
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.5</version>
</dependency>

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
  • upload.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/file/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file"/>
        <input type="submit" value="上传"/>
    </form>
    <img src="${path}">
</body>
</html>

1、input 的 type 设置为 file。

2、form 的 method 设置为 post(get 请求只能将文件名传给服务器)

3、from 的 enctype 设置为 multipart-form-data(如果不设置只能将文件名传给服务器)

  • Handler业务方法
@Controller
@RequestMapping("/file")
public class FileHandler {

    @PostMapping("/upload")
    public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) {
        if (file.getSize() > 0) {
            //获取保存上传文件的file路径
            String path = request.getServletContext().getRealPath("/upload");
            File realpath = new File(path);
            //获取上传的文件名
            String name = file.getOriginalFilename();
            //保存上传之后的文件路径
            System.out.println("上传文件保存地址为:" + realpath);
            if (!realpath.exists())
                realpath.mkdir();
            try {
                file.transferTo(new File(realpath + "/" + name));
                request.setAttribute("path","/upload/" + name);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "upload";
    }
}
  • spring_mvc.xml配置上传组件
<!-- 配置上传组件 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
  • web.xml 配置静态文件(.png和.jpg)过滤,否则客户端无法访问 png和jpg文件
<!--静态png和jpg图片文件不被DispatcherServlet拦截处理-->
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
多文件上传
  • pom.xml还需额外导入jstl和taglibs的jar包
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
  • uploads.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/file/uploads" method="post" enctype="multipart/form-data">
    file1:<input type="file" name="files"/><br/>
    file2:<input type="file" name="files"/><br/>
    file3:<input type="file" name="files"><br/>
    <input type="submit" value="上传"/>
</form>
<c:forEach items="${Files}" var="file">
    <img src="${file}" width="300px">
</c:forEach>
</body>
</html>
  • Handler业务方法
@PostMapping("/uploads")
public String uploads(@RequestParam("files") CommonsMultipartFile[] files,HttpServletRequest request){
    List<String> fileList = new ArrayList<String>();
    for (MultipartFile file:files){
        if(file.getSize()>0){
            //获取保存上传文件的file路径
            String path = request.getServletContext().getRealPath("/upload");
            //获取上传的文件名
            String name = file.getOriginalFilename();
            File realpath = new File(path);
            //如果不存在upload文件夹,就自动创建
            if (!realpath.exists())
                realpath.mkdir();
            try {
                file.transferTo(new File(realpath + "/" + name));
                //保存上传之后的文件路径
                fileList.add("/upload/"+name);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    request.setAttribute("Files",fileList);
    return "uploads";
}
文件下载
  • Handler业务方法
@GetMapping("/download/{name}")
public void download(@PathVariable("name") String name, HttpServletRequest request, HttpServletResponse response){
    if(name != null){
        name += ".png";
        String path = request.getServletContext().getRealPath("/upload");
        File file = new File(path,name);
        OutputStream outputStream = null;
        if(file.exists()){
            response.setContentType("application/forc-download");
            response.setHeader("Content-Disposition","attachment;filename="+name);
            try {
                outputStream = response.getOutputStream();
                outputStream.write(FileUtils.readFileToByteArray(file));
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
  • download.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/file/download/1">1.png</a>
<a href="/file/download/2">2.png</a>
<a href="/file/download/3">3.png</a>
</body>
</html>

后端数据校验

Annotation JSR - 303 标准

使用 Annotation JSR - 303 标准进行验证,需要导入支持这种标准的依赖 jar 文件,这里我们使用 Hibernate Validator。

  • 创建实体Person类
@Data
public class Person {
    @NotEmpty(message = "用户名不能为空")
    private String username;
    @Size(min = 6, max = 12, message = "密码6-12位")
    private String password;
    @Email(message = "请输入正确的邮箱格式")
    private String email;
    @Pattern(regexp = "^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\\d{8}$", message = "请输入正确的电话")
    private String phone;
}
  • 业务方法
@Controller
public class validationHandler {
    @GetMapping("/validator")
    public String register(Model model){
        model.addAttribute("person",new Person());
        return "validator";
    }

    @PostMapping("/validator")
    public String register(@Valid Person person, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "validator";
        }
        return "index";
    }
}
  • validator.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form:form modelAttribute="person" action="/validator" method="post">
    用户名:<form:input path="username"></form:input><form:errors path="username"/><br/>
    密码:<form:password path="password"></form:password><form:errors path="password"/><br/>
    邮箱:<form:input path="email"></form:input><form:errors path="email"/><br/>
    电话:<form:input path="phone"></form:input><form:errors path="phone"/><br/>
    <input type="submit" value="提交"/>
</form:form>
</body>
</html>
  • 测试页面

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Steve_hanhaiLong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值