2020-12-18

spring-mvc第二天笔记整理


springmvc异步请求

页面准备

<a href="javascript:void(0);" id="testAjax">访问springmvc后台controller</a><br/>
<a href="javascript:void(0);" id="testAjaxPojo">访问springmvc后台controller,传递Json格式POJO</a><br/>
<a href="javascript:void(0);" id="testAjaxList">访问springmvc后台controller,传递Json格式List</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnString">访问springmvc后台controller,返回字符串数据</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnJson">访问springmvc后台controller,返回Json数据</a><br/>
<a href="javascript:void(0);" id="testAjaxReturnJsonList">访问springmvc后台controller,返回Json数组数据</a><br/>
<a href="javascript:void(0);" id="testCross">跨域访问</a><br/>
<%--引入jQuery--%>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>

发送和接收异步请求参数

接收异步请求参数,需要在形参前添加**@RequestBody**注解

1)发送并接收简单参数

  • 页面发送请求代码
$("#testAjax").click(function(){
    //发送异步调用
    $.ajax({
       //请求方式:POST请求
       type:"POST",
       //请求的地址
       url:"ajaxController",
       //请求参数(也就是请求内容)
       data:'ajax message',
       //响应正文类型
       dataType:"text",
       //请求正文的MIME类型
       contentType:"text/plain",
    });
});
  • Controller方法
@RequestMapping("/ajaxController")
//使用@RequestBody注解,可以将请求体内容封装到指定参数中
public String ajaxController(@RequestBody String message) {
    System.out.println("ajax request is running..." + message);
    return "page.jsp";
}

注意:异步请求不会发送页面跳转

发送json对象接收并封装成pojo

  • 页面发送请求代码
$("#testAjaxPojo").click(function(){
    $.ajax({
       t ype:"POST",
       url:"ajaxPojoToController",
       data:'{"name":"Jock","age":39}',
       dataType:"text",
       contentType:"application/json",
    });
});

注意:必须通过contentType指定请求数据的类型为json的mime类型application/json

  • Controller方法
@RequestMapping("/ajaxPojoToController")
//如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
//注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
public String ajaxPojoToController(@RequestBody User user) {
    System.out.println("controller pojo :" + user);
    return "page.jsp";
}

异步请求响应数据

1)方法直接返回String并响应

  • 页面发送请求代码
$("#testAjaxReturnString").click(function () {
    //发送异步调用
    $.ajax({
        type: "POST",
        url: "ajaxReturnString",
        //回调函数
        success: function (data) {
            //打印返回结果
            alert(data);
        }
    });
});
  • Controller方法
@RequestMapping(value="/ajaxReturnString",produces = "text/plain;charset=UTF-8")
@ResponseBody
public String ajaxReturnString() {
    System.out.println("controller return string ...");
    return "page.jsp页面";
}

注意:直接返回字符串时,虽然添加了@ResponseBody注解,但是如果响应的字符串中包含中文,会出现中文乱码。需要通过@RequestMapping注解的produces属性指定响应体的mime类型和编码

2)方法返回对象或集合,转成json字符串后响应

  • 页面发送请求代码
//为id="testAjaxReturnJson"的组件绑定点击事件
$("#testAjaxReturnJson").click(function () {
    //发送异步调用
    $.ajax({
        type: "POST",
        url: "ajaxReturnJson",
        //回调函数
        success: function (data) {
            // {"name":"Jockme","age":"39"}  
            alert(data);
            alert(data.name + " ,  " + data['age']);
        }
    });
});

//为id="testAjaxReturnJsonList"的组件绑定点击事件
$("#testAjaxReturnJsonList").click(function () {
    //发送异步调用
    $.ajax({
        type: "POST",
        url: "ajaxReturnJsonList",
        //回调函数
        success: function (data) {
            alert(data);
            alert(data.length);
            alert(data[0]["name"]);
            alert(data[1].age);
        }
    });
});
  • Controller方法
@RequestMapping("/ajaxReturnJson")
@ResponseBody
//基于jackon技术,使用@ResponseBody注解可以将返回的POJO对象转成json格式数据
public User ajaxReturnJson() {
    System.out.println("controller return json pojo...");
    User user = new User();
    user.setName("Jockme");
    user.setAge(39);
    return user;//{"name":"Jockme","age":"39"}
}

@RequestMapping("/ajaxReturnJsonList")
@ResponseBody
//基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
public List ajaxReturnJsonList() {
    System.out.println("controller return json list...");
    User user1 = new User();
    user1.setName("Tom");
    user1.setAge(3);

    User user2 = new User();
    user2.setName("Jerry");
    user2.setAge(5);

    ArrayList al = new ArrayList();
    al.add(user1);
    al.add(user2); // [{"name":"Jockme","age":"39"},{"name":"Jockme","age":"39"}]

    return al;
}

注意:如果是通过springmvc自动将对象或集合转成json字符串,不会出现中文乱码,因为在响应时springmvc会自动指定mime类型和编码
在这里插入图片描述

跨域访问

跨域的概念

在这里插入图片描述
解决方式

在愿意支持跨域访问的Controller方法上添加**@CrossOrigin**注解,就可以支持跨域访问

@RequestMapping("/cross")
@ResponseBody
//使用@CrossOrigin开启跨域访问
@CrossOrigin
public User cross(HttpServletRequest request) {
    System.out.println("controller cross..." + request.getRequestURL());
    User user = new User();
    user.setName("Jockme");
    user.setAge(39);
    return user;
}

注意:@CrossOrigin标注在处理器方法上方表示该方法支持跨域访问,标注在处理器类上表示该处理器类中的所有方法均支持跨域访问

springmvc拦截器

拦截器的概念

相关概念

springmvc中的拦截器Interceptor,类似于web开发中的Filter,一般用于对处理器的方法进行预处理后处理

拦截器(Inteceptor)和过滤器(Filter)的区别

  • Filter属于Servlet技术,只要是web工程均可以使用,Interceptor属于SpringMVC技术,必须有SpringMVC环境才可以使用
  • Filter主要用于对所有请求过滤,拦截器只能拦截DispatcherServlet处理的请求
  • Filter的执行时机早于Interceptor

拦截器使用入门

1)Controller环境准备

@Controller
public class InterceptorController {
    @RequestMapping("/handleRun")
    public String handleRun() {
        System.out.println("业务处理器运行------------main");
        return "/page.jsp";
    }
}

2)自定义拦截器类,实现HandlerInterceptor接口,可根据选择重写preHandle,postHandle,afterCompletion方法

public class MyInterceptor1 implements HandlerInterceptor {
    // 预处理方法,在控制器的方法执行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle1");
        //return false;// 返回true代表放行,返回false代表不放行
        return true;
    }

    // 后处理方法,在处理器执行之后,但是页面跳转之前执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle1");
    }

    // 视图跳转结束之后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion1");
    }
}

3)在spring-mvc.xml文件中配置拦截器

<!--配置拦截器-->
<mvc:interceptors>
    <!--配置具体的拦截器-->
    <mvc:interceptor>
        <!--配置拦截的资源-->
        <mvc:mapping path="/**"/>
        <!--配置拦截器bean对象-->
        <bean class="com.itheima.interceptor.MyInterceptor1"/>
    </mvc:interceptor>
</mvc:interceptors>

拦截器方法详解

  • preHandle方法

    作用:用于对拦截到的请求进行预处理,方法接收boolean类型的返回值,返回true代表放行,返回false代表不放行

    执行时机:在处理器的方法执行之前执行

    方法参数:

    • request:请求对象
    • response:响应对象
    • handler:拦截到的处理器方法
  • postHandle方法

    作用:用于对拦截到的请求进行后处理,可以在方法中对模型数据和视图进行修改

    执行时机:在处理器的方法执行后,视图渲染之前

    方法参数:

    • request:请求对象
    • response:响应对象
    • handler:拦截到的处理器方法
    • modelAndView:处理器方法返回的模型和视图对象,可以在方法中修改模型和视图
  • afterCompletion方法

    作用:用于在整个流程完成之后进行最后处理,如果请求流程中有异常,可以在方法中获取异常对象

    执行时机:视图渲染完成之后(整个流程结束之后)

    方法参数:

    • request:请求对象
    • response:响应对象
    • handler:拦截到的处理器方法
    • ex:异常对象

各方法执行时机图

在这里插入图片描述

拦截器链(多拦截器)

拦截器链的概念

如果多个拦截器能够对相同的请求进行拦截,则多个拦截器会形成一个拦截器链。主要理解拦截器的执行顺序。

拦截器链中多个拦截器的执行顺序

拦截器链中的多个拦截器的执行顺序,跟拦截器的配置顺序有关,先配置的先执行。测试代码如下

MyInterceptor2.java

public class MyInterceptor2 implements HandlerInterceptor {
    // 预处理方法,在控制器的方法执行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle2");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle2");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion2");
    }
}

配置顺序如下:

<!--配置拦截器们-->
<mvc:interceptors>
    <!--配置具体的拦截器-->
    <mvc:interceptor>
        <!--配置拦截的资源-->
        <mvc:mapping path="/**"/>
        <!--配置拦截器bean对象-->
        <bean class="com.itheima.interceptor.MyInterceptor1"/>
    </mvc:interceptor>

    <mvc:interceptor>
        <!--配置拦截的资源-->
        <mvc:mapping path="/**"/>
        <!--配置拦截器bean对象-->
        <bean class="com.itheima.interceptor.MyInterceptor2"/>
    </mvc:interceptor>
</mvc:interceptors>

访问http://localhost/handleRun控制台输出顺序如下:

preHandle1
preHandle2
业务处理器运行------------main
postHandle2
postHandle1
afterCompletion2
afterCompletion1

执行顺序图示

在这里插入图片描述
注意:只要preHandle方法返回true,对应拦截器的afterCompletion方法肯定会执行。如:仅修改MyInterceptor2的preHandle方法返回值为false,虽然整体没有放行,但是MyInterceptor1的afterCompletion方法还是会执行。

拦截器排除静态资源

默认情况下,如果DispatcherServlet的url-pattern配置为/,拦截器的拦截路径配置为/**,那么拦截器会拦截静态资源。但是实际场景中,拦截器通常只负责拦截对于处理器Controller的访问,所以需要排除静态资源,配置方式有两种:

方式1:配置拦截器只拦截对指定前缀Controller方法的访问

<mvc:interceptor>
    <!--配置拦截的资源,只拦截资源路径以/user开始的访问-->
    <mvc:mapping path="/user/**"/>
    <mvc:mapping path="/dept/**"/>
    ....
    <!--配置拦截器bean对象-->
    <bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>

这种方式的缺陷是,首先Controller必须配置一级访问目录。其次,一旦项目中的Controller过多,会出现大量的配置。

方式2:配置拦截器排除指定资源的拦截

<mvc:interceptor>
    <!--配置拦截的资源-->
    <mvc:mapping path="/**"/>
    <!--配置拦截器不拦截的资源-->
    <mvc:exclude-mapping path="/**/*.png"/>
    <mvc:exclude-mapping path="/*/*.css"/>
    <mvc:exclude-mapping path="/**/*.js"/>
    <!--配置拦截器bean对象-->
    <bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>

上述配置中/**/*.png类似的配置,含义为,访问当前项目中任意层级的以.png结尾的资源拦截器都不拦截,如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-isgeZVsT-1608297930845)(排除拦截.png)]

springmvc异常处理

异常处理思路
在这里插入图片描述

基于HandlerExceptionResolver接口实现

此方式了解即可

1)编写异常处理器,实现HandlerExceptionResolver接口,并将该类对象存入spring容器

@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        System.out.println("my exception is running ...."+ex);
        ModelAndView modelAndView = new ModelAndView();
        if( ex instanceof NullPointerException){
            modelAndView.addObject("msg","空指针异常");
        }else if ( ex instanceof  ArithmeticException){
            modelAndView.addObject("msg","算数运算异常");
        }else{
            modelAndView.addObject("msg","未知的异常");
        }
        modelAndView.setViewName("/error.jsp");
        return modelAndView;
    }
}

2)编写用于展示友好提示信息的页面error.jsp

<%--异常消息展示页面--%>
<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>
${msg}

基于@ControllerAdvice注解实现

重点掌握!

1)基础环境

  • ajax.jsp
<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>
<a href="javascript:void(0);" id="testException">访问springmvc后台controller,传递Json格式POJO</a><br/>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.3.1.min.js"></script>

<script type="text/javascript">
    $(function () {
        $("#testException").click(function(){
            $.ajax({
                contentType:"application/json",
                type:"POST",
                url:"findAll",
                data:'{"name":"Jock","age":"18"}',
                dataType:"text",
                //回调函数
                success:function(data){
                    alert(data);
                }
            });
        });
    });
</script>
  • User.java
public class User {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • UserController
@Controller
public class UserController {
    @RequestMapping("/findAll")
    @ResponseBody
    public Result findAll(@RequestBody User user){
        User u1 = new User();
        u1.setName("Tom");
        u1.setAge(3);
        User u2 = new User();
        u2.setName("Jerry");
        u2.setAge(5);
        ArrayList<User> list = new ArrayList<User>();
        list.add(u1);
        list.add(u2);

        return new Result(list,"查询成功", Code.GET_OK);
    }
}
  1. 定义通用的封装响应结果的实体类

在基于异步请求的开发中,为了便于前后台处理,通常会统一返回的json数据的格式,因此通常会自定义封装响应结果的实体类。对于来自前台的一次请求来说,后台需要响应给前台的信息通常是固定的几部分数据:

  1. 是否成功的标识

  2. 成功之后的核心数据

  3. 提示消息(多用于失败之后的消息)

  4. 操作的状态码

对于操作的状态码通常不会临时随意编写,而是预先按照一定的设计规则以常量的形式定义在一个专门的类中

  • 用于封装响应消息的实体类:Result.java
public class Result {
    // 是否成功
    private boolean flag;
    // 成功之后响应的核心数据
    private Object data;
    // 提示消息
    private String message;
    // 操作状态码
    private Integer code;
    // 成功
    public Result(Object data, String message, Integer code) {
        this.flag = true;
        this.data = data;
        this.message = message;
        this.code = code;
    }

    // 失败
    public Result(String message, Integer code) {
        this.flag = false;
        this.message = message;
        this.code = code;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}
  • 用于封装操作结果码的类:Code.java
public class Code {
    //    操作结果编码
    public static final Integer SAVE_OK = 20011;
    public static final Integer UPDATE_OK = 20021;
    public static final Integer DELETE_OK = 20031;
    public static final Integer GET_OK = 20041;

    public static final Integer SAVE_ERROR = 20010;
    public static final Integer UPDATE_ERROR = 20020;
    public static final Integer DELETE_ERROR = 20030;
    public static final Integer GET_ERROR = 20040;

    //    校验结果编码
    public static final Integer DATA_LENGTH_ERROR = 30001;
    public static final Integer DATA_VALUE_ERROR = 30002;
}

3)自定义异常类

需要自定义异常类的原因通常如下:

  1. jdk中默认提供的异常类型过多,不可能在异常处理器中对所有异常进行单独处理
  2. 相同类型的异常可能有不同的原因,因此应该给出不同的提示,而jdk中自带的异常类中并没有与业务相关的提示信息
  3. jdk中默认的异常类型中,没有相关的操作状态码(自定义的状态码)

在自定义异常时,通常选择继承RuntimeException,因为运行时异常不会强制在代码中进行处理,自定义的异常类如下:

public class BusinessException extends RuntimeException {
    // 用于封装错误的状态码
    private Integer code;

    public BusinessException(Integer code) {
        this.code = code;
    }

    public BusinessException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }

    public BusinessException(Throwable cause, Integer code) {
        super(cause);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Integer code) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

4)编写同一个异常处理类

@Component
@ControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Result doBusinessException(BusinessException e){
        // 获取异常的状态的码
        Integer code = e.getCode();
        // 获取异常的提示信息
        String message = e.getMessage();
        // 将其封装到Result对象
        Result result = new Result(message, code);
        return result;
    }
}

5)修改代码进行测试

Controller代码

@RequestMapping("/findAll")
@ResponseBody
public Result findAll(@RequestBody User user){
    if (user.getName().trim().length() < 4){
        // 将其转换成自定义异常
        throw new BusinessException("用户长度必须大于4位",Code.DATA_LENGTH_ERROR);
    }
    if (user.getAge() <= 0){
        throw new BusinessException("年龄必须大于0",Code.DATA_VALUE_ERROR);
    }
    User u1 = new User();
    u1.setName("Tom");
    u1.setAge(3);
    User u2 = new User();
    u2.setName("Jerry");
    u2.setAge(5);
    ArrayList<User> list = new ArrayList<User>();
    list.add(u1);
    list.add(u2);

    return new Result(list,"查询成功", Code.GET_OK);
}

修改页面参数

data:'{"name":"Jo","age":"0"}',
data:'{"name":"Jock","age":"0"}',

springmvc文件上传

单文件上传

实现步骤

1)导入fileupload坐标

<!--文件上传下载-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

2)配置文件上传解析器

<!--配置文件上传的解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--文件上传的总大小-->
    <property name="maxUploadSize" value="20480000"/>
    <!--单个文件的最大大小-->
    <property name="maxUploadSizePerFile" value="2048000"/>
    <!--解决中文文件名的乱码问题,如果web.xml中配置了中文乱码过滤器,可以不进行配置-->
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

注意事项:CommonsMultipartResolver对象的id必须为multipartResolver,因为DispatcherServlet中已经将这个值写死:
在这里插入图片描述
3)编写文件上传页面

<form action="upload" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="imgFile"/><br>
    <button type="submit">上传</button>
</form>

4)编写Controller中实现文件上传的方法

@Controller
public class FileUploadController {
    @RequestMapping("/upload")
    public String upload(MultipartFile imgFile, HttpServletRequest request) {
        // 判断文件数据是否为空
        if (!imgFile.isEmpty()) {
            // 1获取文件名
            String fileName = imgFile.getOriginalFilename();
            String uuid = UUID.randomUUID().toString();
            // 1.2 解决文件名重名
            fileName = uuid + "_" + fileName;
            // 2将文件数据保存到硬盘上
            // 2.1 动态获取images目录的绝对路径
            ServletContext context = request.getServletContext();
            String realPath = context.getRealPath("/images");
            // 2.2 创建File对象
            File file = new File(realPath, fileName);
            try {
                imgFile.transferTo(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "/page.jsp";
    }
}

多文件上传

1)修改表单,添加多个file类型的表单项

<form action="upload" method="post" enctype="multipart/form-data">
    选择文件1:<input type="file" name="imgFiles"/><br>
    选择文件1:<input type="file" name="imgFiles"/><br>
    <button type="submit">上传</button>
</form>

注意:多个表单项的name属性值一致

2)修改Controller中的方法,修改参数类型为MultipartFile[]数组

@Controller
public class FileUploadController {
    @RequestMapping("/upload")
    public String upload(MultipartFile[] imgFiles,HttpServletRequest request){
        for (MultipartFile imgFile : imgFiles) {
            // 判断文件数据是否为空
            if(!imgFile.isEmpty()){
                // 1获取文件名
                String fileName = imgFile.getOriginalFilename();
                String uuid = UUID.randomUUID().toString();
                // 1.2 解决文件名重名
                fileName=uuid+"_"+fileName;
                // 2将文件数据保存到硬盘上
                // 2.1 动态获取images目录的绝对路径
                ServletContext context = request.getServletContext();
                String realPath = context.getRealPath("/images");
                // 2.2 创建File对象
                File file = new File(realPath, fileName);
                try {
                    imgFile.transferTo(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "/page.jsp";
    }
}

核心对象:

  • MultipartFile

    用于封装上传的文件相关数据

核心方法:

  • isEmpty()

    判断文件数据是否为空,false代表不为空

  • getOriginalFilename()

    获取文件名

  • transferTo()

    将文件数据转移到一个file中(将文件数据写入到硬盘的某个文件中)

注意事项:

  • MultipartFile类型的参数名必须和file类型的表单项的name属性值保持一致

springmvc之Restful风格

什么是Restful?

restful 是一套网络接口的设计风格,通过资源+请求方式描述对资源的不同操作

以用户模块的增删改查操作为例,传统风格和restful风格的设计方式分别如下:
在这里插入图片描述

同步请求使用Restful

  1. 过滤器配置
<!--配置拦截器,解析请求中的参数_method,否则无法发起PUT请求与DELETE请求,配合页面表单使用-->
<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)页面代码

<h2>同步请求</h2>
<h3>查询单个用户</h3>
<a href="/user/1">查询用户</a>
<h3>保存用户</h3>
<form action="/user" method="post">
    用户名:<input type="text" name="name"/><br>
    年龄:<input type="number" name="age"></br>
    <button type="submit">保存</button>
</form>

<h3>删除用户</h3>
<form action="/user/2" method="post">
    <input type="hidden" name="_method" value="delete">
    <button type="submit">删除</button>
</form>

<h3>更新用户</h3>
<form action="/user" method="post">
    <input type="hidden" name="_method" value="PUT">
    用户名:<input type="text" name="name"/><br>
    年龄:<input type="number" name="age"></br>
    <button type="submit">更新</button>
</form>
  1. Controller 方法
/*@Controller
@ResponseBody*/
@RestController
@RequestMapping("/user")
public class UserController {
    //@RequestMapping(value = "/{id}",method = RequestMethod.GET )
    @GetMapping("/{id}")
    public String findUser(@PathVariable("id") int uid){
        System.out.println("查询"+uid+"号用户");
        return "findUser";
    }

    //@RequestMapping(method = RequestMethod.POST)
    @PostMapping()
    public String saveUser(String name,int age){
        System.out.println("保存用户");
        System.out.println(name+","+age);
        return "saveUser";
    }

    // @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable("id") int uid){
        System.out.println("删除"+uid+"号用户");
        return "deleteUser";
    }

    // @RequestMapping(method = RequestMethod.PUT)
    @PutMapping()
    public String updateUser(String name,int age){
        System.out.println("更新用户");
        System.out.println(name+","+age);
        return "updateUser";
    }
}

代码解释:

  • 路径中的参数值不是固定的,所以通过${变量名}表示这是一个路径中的变量

  • @PathVariable

    表示将指定名称的路径变量对应的值,赋值给方法形参

  • @RestController

    相当于@Controller+@ResponseBody

  • @GetMapping

    相当于@RequestMapping(method = {RequestMethod.GET})

    其它同理

异步请求使用Restful

异步请求可以直接发球PUT或DELETE请求,因此可以不配置HiddenHttpMethodFilter过滤器

1)页面发起请求代码

<script src="js/jquery-3.3.1.min.js"></script>
<script>
    function deleteUser() {
        $.ajax({
            url: "${pageContext.request.contextPath}/user/10",
            type: "DELETE"
        })
    }

    function updateUser() {
        $.ajax({
            url: "${pageContext.request.contextPath}/user/3",
            type: "PUT"
        })
    }

    function saveUser() {
        $.ajax({
            url: "${pageContext.request.contextPath}/user",
            type: "POST",
            data:'name=zhangsan&age=10'
        })
    }
</script>

<h2>ajax异步请求</h2>
<hr>
<input type="button" value="删除账户" οnclick="deleteAccount();"> 
<input type="button" value="修改账户" οnclick="updateAccount();">
<input type="button" value="查询账户" οnclick="findAccount();">
<input type="button" value="添加账户" οnclick="saveAccount();">

需要添加一个新的updateUser方法

@PutMapping("/{id}")
public String updateUser(@PathVariable int id){
    System.out.println("更新用户"+id);
    return "updateUser";
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值