SpringMVC学习笔记(二)域对象、视图、RESTful及案例

一、域对象共享数据

  1. 域对象
    (1)Request:一次请求。
    (2)Session:一次会话,浏览器开启到浏览器关闭。
        假设我们在淘宝中用户过多的时候,虽然 session 没有下限,但 session 的数量就会不断增多。之后就会导致内存无法承受,此时就会有一些 session 长时间都没有活动。服务器启动时就会将这些很久没有活动的 session 放到硬盘上,让内存给空出来。就会使得很多的session被保存到硬盘上以此来空出内存。而即便之后需要再次访问 session,它就会再次从硬盘中将 session给放到内存中来使用。这样用户就不会感觉到自己掉线了。这个过程就是 session 的钝化和活化。
    钝化:服务器关闭了,但浏览器未关闭会话还在继续,这个时候Session中的数据通过序列化保存到磁盘中。
    活化:将磁盘中序列化保存的Session信息读取到Session中。
    (3)ServletContext/Application:整个应用开启到关闭,服务器开启到服务器关闭。

  2. 共享数据的实现
    (1)转发可以获取请求域中的数据,因为转发本质上是一次请求。
    (2)会话共享数据:因为Cookie中保存了JSESSION_ID,只要有JSESSION_ID创建的Session永远是同一个
    (3)ServletContext共享数据:因为ServletContext只会在服务器开启时创建一次,服务器关闭时销毁,调用的都是同一个对象。

  3. 域对象的使用选择
    (1)查询列表,表单回显使用Request域。
    (2)通常推荐选择能、实现功能的范围最小的域。

1、使用ServletAPI向request域对象共享数据

@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
    request.setAttribute("testScope", "hello,servletAPI");
    return "success";
}

(1)操作共享域数据的三种方法:setAttribute()、getAttribute()、removeAttribute()
(2)return"视图名",本质是转发
(3)th:text=“${内容}“中,
①要使用request域中的数据,直接写键名;
②要使用session域中的数据,写session.键名
③要使用servletContext域中的数据,写application.键名
(3)th:href =”@{内容}”,内容写请求地址

2、使用ModelAndView向request域对象共享数据

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

3、使用Model向request域对象共享数据

@RequestMapping("/testModel")
    public String testModel(Model model){
        model.addAttribute("testScope","Hello,Model");
        return "test";
    }

4、使用map向request域对象共享数据

@RequestMapping("/testMap")
    public String testMap(Map<String,Object> map){
        map.put("testScope","Hello,Map");
        return "test";
    }

5、使用ModelMap向request域对象共享数据

@RequestMapping("/testModelMap")
    public String testModelMap(ModelMap modelMap){
        modelMap.addAttribute("testScope","Hello,ModelMap");
        return "test";
    }

6、Model、ModelMap、Map的关系

Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的

public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}

View是视图信息,Model是通过域传递的内容。
不管用的是什么方式,最终都会把内容封装到ModelAndView对象中。

7、向session域共享数据

使用原生Sevlet共享数据。

@RequestMapping("/testSession")
    public String testSession(HttpSession httpSession){
        httpSession.setAttribute("testSessionScope","Hello,Session");
        return "test";
    }

8、向application域共享数据

  1. 如何获取ServletContext对象
    (1)JSP页面中的pageContext对象可以获取ServletContext对象
    (2)request可以获取ServletContext对象
    (3)servlet的init方法中有一个对象ServletConfig可以获得ServletContext对象
@RequestMapping("/testApplication")
    public String testSerlvetContext(HttpSession httpSession){
        ServletContext servletContext = httpSession.getServletContext();
        servletContext.setAttribute("testApplicationScope","Hello,Application");
        return "text";
    }
  1. 各类域对象使用场景
    (1)Request:列表、修改回显、错误信息
    (2)Session:保存用户的登陆状态,Session默认30分钟后失效

二、SpringMVC的视图

SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户
SpringMVC视图的种类很多,默认有InternalResourceView转发视图和RedirectView重定向视图
当工程引入jstl的依赖,转发视图会自动转换为JstlView
若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView

1、ThymeleafView

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

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

在这里插入图片描述

2、转发视图

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

@RequestMapping("/testForward")
public String testForward(){
    return "forward:/testHello";
}

(1)创建两次视图,第一次创建转发视图,第二次创建转发到的地址的视图。
(2)如果要转发到具体某一个html页面,请求地址不能写具体的页面,因为页面是thymeleaf动态渲染的,所有请求必须通过thymeleaf解析,写具体的页面就解析不了了,所以要通过转发到一个能处理thymeleaf页面的请求来跳转。
在这里插入图片描述

3、重定向视图

SpringMVC中默认的重定向视图是RedirectView
当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:“去掉,剩余部分作为最终路径通过重定向的方式实现跳转
例如"redirect:/”,“redirect:/employee”
由于重定向不能访问WEB-INF目录下的文件,而页面都存在在WEB-INF下,所以重定向的请求地址也不能写具体的路径,必须要写另一个请求的地址。

@RequestMapping("/testRedirect")
public String testRedirect(){
    return "redirect:/testHello";
}

在这里插入图片描述

转发和重定向的区别
(1)转发是一次请求,重定向是两次请求,第一次访问servlet,第二次访问重定向地址
(2)转发地址不会改变,重定向地址会改变
(3)转发可以获取request域中的对象,重定向因为是两次请求所以不可以
(4)转发能访问WEB-INF目录下的资源,重定向不可以
(5)转发不能跨域,重定向可以跨域

4、视图控制器view-controller

当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示。
是SpringMVC中的一个标签。

<!--
    path:设置处理的请求地址
    view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>

注:
当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需
要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:
<mvc:annotation-driven />

5、SpringMVC自带的视图解析器InternalResourceView

在SpringMVC.xml中配置

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/templates/"></property>
        <property name="suffix" value=".jsp"></property>
</bean>

三、RESTful

1、RESTful简介

REST:Representational State Transfer,表现层资源状态转移。
a>资源
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。
b>资源的表述
资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。
c>状态转移
状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。

2、RESTful的实现

具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE用来删除资源。
REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。

操作传统方式REST风格
查询操作getUserById?id=1user/1–>get请求方式
保存操作saveUseruser–>post请求方式
删除操作deleteUser?id=1user/1–>delete请求方式
更新操作updateUseruser–>put请求方式

3、HiddenHttpMethodFilter

由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?
SpringMVC 提供了HiddenHttpMethodFilter帮助我们将 POST 请求转换为 DELETE 或 PUT 请求

HiddenHttpMethodFilter 处理put和delete请求的条件:
a>当前请求的请求方式必须为post
b>当前请求必须传输请求参数_method

  1. 源码分析
    在这里插入图片描述

3.1 模拟PUT请求

(1)在web.xml中注册HiddenHttpMethodFilter

<!-- 配置HiddenHttpMethod过滤器 -->
    <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>测试put方法</h2>
<form th:action="@{/user}" method="post">
    <input type="hidden" name="_method" value="put">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="修改">
</form>

(3)Controller

    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String updateUser(String username,String password){
        System.out.println("PUT方法");
        System.out.println("username:"+username+",password:"+password);
        return "test";
    }

3.2 和CharacterEncodingFilter的关系

目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter
在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter原因:

  1. 在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的
  2. request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作
  3. 而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:String paramValue = request.getParameter(this.methodParam)

四、RESTful案例

1、准备工作

  1. Employee实体类
package com.yuuto148.mvc.bean;
import org.springframework.stereotype.Component;
@Component
public class Employee {
    private Integer id;
    private String lastName;
    private Integer gender;
    private String email;

    public Employee() {
    }

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

    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 Integer getGender() {
        return gender;
    }

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

    public String getEmail() {
        return email;
    }

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

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", gender=" + gender +
                ", email='" + email + '\'' +
                '}';
    }
}
  1. DAO
package com.yuuto148.mvc.dao;

import com.yuuto148.mvc.bean.Employee;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

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

        employees.put(1001, new Employee(1001, "E-AA", 1, "aa@163.com"));
        employees.put(1002, new Employee(1002, "E-BB", 1, "bb@163.com"));
        employees.put(1003, new Employee(1003, "E-CC", 0, "cc@163.com"));
        employees.put(1004, new Employee(1004, "E-DD", 0, "dd@163.com"));
        employees.put(1005, new Employee(1005, "E-EE", 1, "ee@163.com"));
    }

    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);
    }
}

2、功能清单

功能URL地址请求方式
查询所有人员/employeeGET
删除/employee/2DELETE
新增人员/employeePOST
更新人员/employeePUT

具体功能:访问首页

a>配置view-controller

<mvc:view-controller path="/restIndex" view-name="restIndex"></mvc:view-controller>

b>创建页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a th:href="@{/employee}">查询所有人员</a>
</body>
</html>

具体功能:查询所有员工

a>控制器方法

@Controller
public class RestExampleController {
    @Autowired
    private EmployeeDao dao;
    @RequestMapping(value = "/employee", method = RequestMethod.GET)
    public String getEmployeeList(Model model){
        Collection<Employee> employeeList = dao.getAll();
        model.addAttribute("employeeList",employeeList);
        return "employee_list";
    }
}

b>employee_list页面

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

具体功能:删除

a>创建处理delete请求方式的表单

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

b>删除超链接绑定点击事件
引入vue.js

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

删除超链接

 <a @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>

通过vue处理点击事件

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

c>控制器方法

 @RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
    public String deleteEmployee(@PathVariable("id") Integer id){
        dao.delete(id);
        return "redirect:/employee";
    }

mvc开启静态资源的访问

<mvc:default-servlet-handler></mvc:default-servlet-handler>

具体功能:添加员工

a>添加a标签

 <th>options(<a th:href="@{/toAdd}">Add</a>)</th>

b>添加映射

<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>

c>编写employee_add页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>添加新员工</title>
</head>
<body>
    <form th:action="@{/employee}" method="post">
        lastName:<input type="text" name="lastName"><br>
        email:<input type="text" name="email"><br>
        gender:<input type="radio" name="gender" value="1">male
        <input type="radio" name="gender" value="0">female<br>
        <input type="submit" value="add"><br>
    </form>
</body>
</html>

d>编写控制器方法

@RequestMapping(value = "/employee", method = RequestMethod.POST)
    public String addEmployee(Employee employee){
        dao.save(employee);
        return "redirect:/employee";
    }

具体功能:更新员工

a>添加超链接

<a th:href="@{'/employee/'+${employee.id}}">update</a>

b>控制器中配置跳转方法

@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET)
    public String getEmployeeById(@PathVariable("id") Integer id, Model model){
        Employee employee = dao.get(id);
        model.addAttribute("employee",employee);
        return "employee_update";
    }

c>编写employee_update页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>更新人员信息</title>
</head>
<body>
    <form th:action="@{/employee}" method="post">
      <input type="hidden" name="_method" value="put">
      <input type="hidden" name="id" th:value="${employee.id}">
      lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br>
      email:<input type="text" name="email" th:value="${employee.email}"><br>
      <!--
          th:field="${employee.gender}"可用于单选框或复选框的回显
          若单选框的value和employee.gender的值一致,则添加checked="checked"属性
       -->
      gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male
      <input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br>
      <input type="submit" value="add"><br>
    </form>
</body>
</html>

d>编写控制器代码

@RequestMapping(value = "/employee", method = RequestMethod.PUT)
    public String updateEmployee(Employee employee){
        dao.save(employee);
        return "redirect:/employee";
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值