SpringMVC笔记02 域对象共享数据,视图,RESTFul,HttpMessageConverter,文件上传下载

域对象共享数据

使用servletAPI(向request域对象共享数据)

使用ModelAndView(向request域对象共享数据)

测试:

使用Model(向request域对象共享数据)

使用Map(向request域对象共享数据)

使用ModelMap(向request域对象共享数据)

Model,Map,ModelMap的关系

通过反射获取方法形参中三者的类型均为

class org.springframework.validation.support.BindingAwareModelMap

继承关系如下

这个类可用来创建三者的实例化对象


源码解析:控制器方法执行后都会返回统一的ModelAndView对象

向session域共享数据

向application域共享数据

SpringMVC的视图

SpringMVC中的视图时View接口,视图的作用渲染数据,将模型Model中的数据展示给用户

SpringMVC视图的种类很多,默认有转发视图InternalResourceView和重定向视图RedirectView

当工程引入jstl的依赖,转发视图会自动转换为jstlView

若使用视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView

ThymeleafView

当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转。

转发视图

SpringMVC中默认的转发视图是InternalResourceView

SpringMVC中创建转发视图的情况:

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

重定向视图

SpringMVC中默认的重定向视图时RedirectView

当控制器方法中所设置的视图名称以“redirect:”为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件所配置的视图解析器解析,而是会将前缀“redirect:”去掉,剩余部分作为最终路径通过重定向的方式实现跳转

视图控制器view-controller

springMVC.xml

配置了view-controller之后,控制器中所有的请求映射全部失效,需要开启MVC注解驱动

视图解析器InternalResourceViewResolver

RESTFul

简介

是一种软件架构的风格(格式)

REST:Representational State Transfer,表现层资源状态转移

资源

是一种看待服务器的方式,即将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念,所以它不仅仅能代表服务器文件系统中的一个文件,数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象。只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web服务器上的地址,对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。

资源的表述

资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器之间转移(交换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定,请求-响应方向的表述通常使用不同的格式。

状态转移

状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源的表述,通过转移和操作资源的表述,来间接实现操作资源的目的。

RESTFul的实现

具体说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。

它们分别对应四种基础操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。

REST风格提倡的是地址使用统一的风格设计,从前到后各个单词用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发生给服务器的数据作为URL地址的一部分,以保证整体风格的一致性。

使用RESTFul模拟操作用户资源(get和post请求)

@Controller
public class UserController {
    /**
     * 使用RESTFul模拟用户资源的增删改查
     * /users  GET     查询所有用户信息
     * /user/1 GET     根据用户id查询所有用户信息
     * /user   POST    添加用户信息
     * /user/1 DELETE  删除用户信息
     * /user   PUT     更新用户信息
     */
    @RequestMapping(value = "/users", method = RequestMethod.GET)
    public String getAllUser() {
        System.out.println("查询所有用户信息");
        return "success";
    }

    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    public String getUserById() {
        System.out.println("根据id查询用户信息");
        return "success";
    }

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    public String insertUser(String username, String password) {
        System.out.println("添加用户,username:" + username + "password:" + password);
        return "success";
    }
}

测试

HiddenHttpMethodFilter处理PUT和DELETE请求方式

编码过滤器和HiddenHttpMethodFilter的顺序:编码过滤器顺序在前。

查看源码

模拟PUT和DELETE请求

 

但是一般删除都是超链接,需要绑定单击事件,取消默认跳转,并提交表单。

RESTFul案例

和传统CRUD一样,实现对员工信息的增删改查

准备工作

Employee实体类

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;

    public Employee() {
    }

    public Employee(Integer id, String lastName, String email, Integer gender) {
        this.id = id;
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                '}';
    }
}

 EmployeeDao

@Repository
public class EmployeeDao {
    private static Map<Integer, Employee> employees = null;

    static {
        employees = new HashMap<Integer, Employee>();
        employees.put(1001, new Employee(1001, "HUI", "111.@qq.com", 1));
        employees.put(1002, new Employee(1002, "DSA", "321.@qq.com", 0));
        employees.put(1003, new Employee(1003, "SSD", "133.@qq.com", 0));
        employees.put(1004, new Employee(1004, "FSA", "123.@qq.com", 1));
        employees.put(1005, new Employee(1005, "GFS", "153.@qq.com", 0));
    }

    private static Integer initId = 1006;

    public void save(Employee employee) {
        if (employee.getId() == null) {
            employee.setId(initId++);
        }
        employees.put(employee.getId(), employee);
    }

    public Collection<Employee> getAll() {
        return employees.values();
    }

    public Employee get(Integer id) {
        return employees.get(id);
    }

    public void delete(Integer id) {
        employees.remove(id);
    }
}

功能实现

查看全部员工信息 


删除功能

注意:超链接路径

新建文件夹

在页面中引入vue.js,并为超链接添加单击事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
    <title>员工信息</title>
</head>
<body>
<table id="dataTable" border="1" cellspacing="0" cellpadding="0" style="text-align: center;">
    <tr>
        <th colspan="5">Employee Info</th>
    </tr>
    <tr>
        <th>id</th>
        <th>lastName</th>
        <th>email</th>
        <th>gender</th>
        <th>options</th>
    </tr>
    <tr th:each="employee:${employeeList}">
        <td th:text="${employee.id}"></td>
        <td th:text="${employee.lastName}"></td>
        <td th:text="${employee.email}"></td>
        <td th:text="${employee.gender}"></td>
        <td>
            <a @click="deleteEmployee" th:href="@{/employee/}+${employee.id}">delete</a>
            <a href="">update</a>
        </td>
    </tr>
</table>

<form id="deleteForm" method="post">
    <input type="hidden" name="_method" value="delete">
</form>

<script type="text/javascript" th:src="@{/static/js/vue.min.js}"></script>

<script type="text/javascript">
    var vue = new Vue({
        el: "#dataTable",
        methods: {
            deleteEmployee: function (event) {
                var deleteForm = document.getElementById("deleteForm");
                //将触发点击事件的超链接的href属性赋值给表单的action
                deleteForm.action = event.target.href;
                //提交表单
                deleteForm.submit();
                //取消超链接默认行为
                event.preventDefault();
            }
        }
    });
</script>

</body>
</html>

测试,依然报错405

是由于当前工程打包的结果没有static目录,需要重新打包

但是此时还是不行,因为此时访问静态资源,是由DispatcherServlet处理的。

配置springMVC.xml

​​​​​

配置之后,先由springMVC处理请求映射,如果没找到将当前请求交给默认Servlet处理。


实现添加功能

employee_add.html

测试

添加成功!


修改功能

employee_update.html 

复选框内容会自动与value值进行比较,一致则勾选

完成

HttpMessageConverter

HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文,HttpMessageConvert提供了两个注解和两个类型:@RequestBody,@ResponseBody

RequestEntity,ResponseEntity

@RequestBody

可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值

RequestEntity

RequestEntity封装请求报文的一种类型,需要在控制器方法的形参在设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息

  

输出结果

requestHeader:[host:"localhost:8080", connection:"keep-alive", content-length:"57", cache-control:"max-age=0", sec-ch-ua:"" Not A;Brand";v="99", "Chromium";v="100", "Microsoft Edge";v="100"", sec-ch-ua-mobile:"?0", sec-ch-ua-platform:""Windows"", upgrade-insecure-requests:"1", origin:"http://localhost:8080", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.50", accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", sec-fetch-site:"same-origin", sec-fetch-mode:"navigate", sec-fetch-user:"?1", sec-fetch-dest:"document", referer:"http://localhost:8080/springMVC_demo4/", accept-encoding:"gzip, deflate, br", accept-language:"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", cookie:"Idea-6aaab5b3=171a0ae7-91ce-403b-9084-01fc843ac0d3", Content-Type:"application/x-www-form-urlencoded;charset=UTF-8"]
requestBody:username=%E5%A4%A7%E8%8B%8F%E6%89%93144&password=153435hj

@ResponseBody

用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器

SpringMVC处理json

第一步:导入jackson依赖

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.1</version>
        </dependency>

 第二步:在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConvert,可以将响应到浏览器的Java对象转换为Json格式的字符串

 

第三步:在处理器方法上使用@ResponseBody注解进行标识

第四步:将Java对象直接作为控制器方法的放回值返回,就会自动转换为Json格式的字符串

 

SpringMVC处理ajax

导入所需资源 

<div id="app">
    <a @click="testAxios" th:href="@{/testAxios}">springMVC处理ajax</a>
</div>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript" th:src="@{/static/js/vue.min.js}"></script>
<script type="text/javascript">
    var vue = new Vue({
        el: "#app",
        methods: {
            testAxios: function (event) {
                axios({
                    method: "post",
                    url: event.target.href,
                    params: {
                        username: "admin",
                        password: "123456"
                    }
                }).then(function (response) {
                    alert(response.data);
                });
                event.preventDefault();
            }
        }
    });
</script>

@RestController注解

@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解

ResponseEntity

用于控制器方法的返回值类型,该控制器的方法的返回值就是响应到浏览器的响应报文

文件上传和下载

文件下载

使用ResponseEntity实现下载文件的功能

    @RequestMapping("/testDownLoad")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //获取ServletContext对象
        ServletContext context = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath = context.getRealPath("/static/img/vs2.jpg");
        //创建输入流
        FileInputStream is = new FileInputStream(realPath);
        //创建字节数组
        byte[] bytes = new byte[is.available()];
        //将流读入到字节数组中
        is.read(bytes);
        //创建HttpHeader对象设置响应头信息
        MultiValueMap<String, String> headers = new HttpHeaders();
        //设置要下载方式以及下载文件的名字
        headers.add("Content-Disposition", "attachment;filename=1.jpg");
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
        //关闭输入流
        is.close();
        return responseEntity;
    }

文件上传

引入依赖

配置SpringMVC的文件上传解析器

    <!--配置文件上传解析器,将上传的文件封装为MultipartFile-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

代码

    @RequestMapping("/testUp")
    public String testUp(MultipartFile photo, HttpSession session) throws IOException {
        //获取上传的文件的文件名
        String filename = photo.getOriginalFilename();
        //解决文件的重名问题
        //获取上传的文件的后缀名
        String suffixName = filename.substring(filename.lastIndexOf("."));
        //将UUID作为文件名
        String uuid = UUID.randomUUID().toString();
        //将uuid和后缀名拼接后的结果作为最终的文件名
        filename = uuid + suffixName;
        //通过ServletContext获取服务器中photo目录的路径
        ServletContext context = session.getServletContext();
        String photoPath = context.getRealPath("photo");
        File file = new File(photoPath);
        //判断photoPath所对应路径是否存在
        if (!file.exists()) {
            file.mkdir();
        }
        String finalPath = photoPath + File.separator + filename;
        photo.transferTo(new File(finalPath));
        return "success";
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值