【SpringMVC】【域对象共享数据】【SpringMVC的视图】【RESTful】【学习笔记】Spring开学很好学1.4

域对象共享数据

1、向request域对象共享数据

1.1、ServletAPI

HttpServletRequest对象,作为控制器方法的形参

setAttribute()方法 : 存数据

@RequestMapping(value = "/test")
public String test(HttpServletRequest request){
    request.setAttribute("k","v");
    return "success";
}

1.2、ModelAndView(推荐)

Model : 主要用于请求域共享数据

addObject()方法 : 存数据

View : 主要用于设置视图,实现页面跳转

setViewName()方法 : 设置视图信息

@RequestMapping(value = "/test")
public ModelAndView test(){
    ModelAndView mav = new ModelAndView();
    mav.addObject("k1","ModelAndView");
    mav.setViewName("success");
    return mav;
}
<!-- 如果是请求域的数据直接写k就可以取v -->
<p th:text="${k1}"></p>

1.3、Model

Model对象,可以作为控制器方法的形参

addAttribute()方法 : 存数据

@RequestMapping( "/test")
public String test(Model model){
    model.addAttribute("k1","mode");
    return "success";
}

1.4、Map

Map对象,可以作为控制器方法的形参

put()方法 : 存数据

@RequestMapping( "/test")
public String test(Map<String,String> map){
    map.put("k1","map");
    return "success";
}

1.5、ModelMap

ModelMap对象,可以作为控制器方法的形参

addAttribute()方法 : 存数据

@RequestMapping( "/test")
public String test(ModelMap modelMap){
    modelMap.addAttribute("k1","modelMap");
    return "success";
}

2、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 {}

3、控制器方法执行之后,都会返回统一的ModelAndView对象

在这里插入图片描述

这里modle为什么没有值,因为我们用的是原生的ServletAPI

@RequestMapping( "/test")
public String test(HttpServletRequest request){
    request.setAttribute("k1","HttpServletRequest");
    return "success";
}

下面不用原生的ServletAPI就可以看到值

在这里插入图片描述

@RequestMapping( "/test")
public String test(Map<String,String> map){
    map.put("k1","map");
    return "success";
}

3、向session域共享数据

HttpSession对象,可以作为控制器方法的形参

setAttribute()方法 : 存数据

@RequestMapping( "/test")
public String test(HttpSession session){
    session.setAttribute("sessionK","sessionV");
    return "success";
}
<!--通过session.的方式获取session域中的数据-->
<p th:text="${session.sessionK}"></p>

4、向application域共享数据

HttpSession对象,可以作为控制器方法的形参,之后通过getServletContext()方法获取application对象

setAttribute()方法 : 存数据

@RequestMapping( "/test")
public String test(HttpSession session){
    ServletContext application = session.getServletContext();
    application.setAttribute("applicationK","applicationV");
    return "success";
}

SpringMVC的视图

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

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

举例

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

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

1、ThymeleafView

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

在这里插入图片描述

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

细🔒1下

DispatcherServlet

// 返回ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 拦截器的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);


// 处理ModelAndView的视图信息,执行转发结果
 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

processDispatchResult()方法,部分

if (mv != null && !mv.wasCleared()) {
    this.render(mv, request, response);	// render()方法
    if (errorView) {
        WebUtils.clearErrorRequestAttributes(request);
    }

render()方法

....
    Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();	// 本地化zh_CH
...
    View view;
	String viewName = mv.getViewName();		// 获取视图名称
if (viewName != null) {
    view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request); // 解析视图名称获取视图对象

ModelAndView 类的 getModelInternal() 方法

@Nullable
protected Map<String, Object> getModelInternal() {
    return this.model;
}

2、InternalResourceView

SpringMVC中默认的转发视图是InternalResourceView

SpringMVC中创建转发视图的情况

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

代码实现

这里,我们用testForward 转发访问 testThymeleafView ,第一次是InternalResourceView

在这里插入图片描述

第二次,访问success,就是ThymeleafView

在这里插入图片描述

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

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

3、RedirectView

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

定向的方式实现跳转 例如redirect:/redirect:/testThymeleafView

在这里插入图片描述

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

@RequestMapping("/testDirect")
public String testDirect(){
    return "redirect:/testThymeleafView";
}

4、view-controller

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

path属性 :

view-name属性 :

<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
@RequestMapping("/")
public String index(){return "index";}

当我们在springMVC的文件中配置了view-controller,控制器的所有的请求映射都会失效

<!-- 开启MVC注解驱动 -->
<mvc:annotation-driven/>

RESTful

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

1、RESTful的实现

操作传统方式REST风格
查询getUserById?id=1user/1
保存saveUseruser
删除deleteUser?id=1user/1
更新updateUseruser

2、HiddenHttpMethodFilter

可以将 POST 请求转化为 DELETEPUT 请求

web.xml中注册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>

xmlfilter的顺序按照filter-mapping顺序,所以必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter

源码细🔒

我们来到HiddenHttpMethodFilterdoFilterInternal()方法

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    HttpServletRequest requestToUse = request;
    // 所以,首先需要是POST请求
    if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
        // 我们在源码中找找methodParam
        String paramValue = request.getParameter(this.methodParam); 
        if (StringUtils.hasLength(paramValue)) {
            String method = paramValue.toUpperCase(Locale.ENGLISH);
         	// 我们在源码中找找ALLOWED_METHODS
            if (ALLOWED_METHODS.contains(method)) { 
                // 创建一个新的请求对象
                requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
            }
        }
    }
    // 放行的时候,放的是新创建的请求对象
    filterChain.doFilter((ServletRequest)requestToUse, response);
}

下面为methodParam

private String methodParam = "_method";

下面为ALLOWED_METHODS

static {
    ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
    // 我们接着看看HttpMethod是什么 
}

HttpMethod是一个枚举

public enum HttpMethod {
    GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE;
...

代码实现

<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_method" value="DELETE">

RESTful案例

在这里插入图片描述

1、代码实现

功能URL地址请求方式
访问首页/GET
查询全部数据/employeeGET
删除/employee/1DELETE
跳转到添加数据页面/toAddGET
执行保存/employeeGET
跳转到更新页面数据/employee/1GET
执行更新/employeePUT

员工Bean

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    // 1 male   0 female
    private Integer gender;
   	...
}

模拟Dao层

@Repository
public class EmployeeDao {
    private static Map<Integer, Employee> employees = null;
    // 初始员工信息
    static {
        employees = new HashMap<Integer, Employee>();
        employees.put(1,new Employee(1,"A","A@flzj.com",1));
        employees.put(2,new Employee(2,"B","B@flzj.com",0));
        employees.put(3,new Employee(3,"C","C@flzj.com",0));
        employees.put(4,new Employee(4,"D","D@flzj.com",1));
    }
    private static Integer initId = 5;
    // 保存员工信息
    public void save(Employee employee){
        if(employee != null) {
            if(employee.getId() == null) {
                employee.setId(initId++);
            }
            employees.put(employee.getId(),employee);
        }
    }
    // 返回全部员工信息
    public Collection<Employee> getAll(){
        return employees.values();
    }
    // 通过id获取员工信息
    public Employee get(Integer id){
        return employees.get(id);
    }
    // 通过id删除员工信息
    public void delete(Integer id){
        employees.remove(id);
    }

}

Controller层

@Controller
public class EmployeeController {

    @Autowired
    private EmployeeDao employeeDao;

    @RequestMapping(value = "/employee", method = RequestMethod.GET)
    public String getAllEmployee(Model model){
        Collection<Employee> employeeList = employeeDao.getAll();
        model.addAttribute("employeeList", employeeList);
        return "employee_list";
    }

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

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

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

    @RequestMapping(value = "/employee", method = RequestMethod.PUT)
    public String updateEmployee(Employee employee){
        employeeDao.save(employee);
        return "redirect:/employee";
    }

}

员工列表 employee_list.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Employee Info</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(<a th:href="@{/toAdd}">add</a></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 th:href="@{'/employee/'+${employee.id}}">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.js}"></script>
    <script type="text/javascript">
        var vue = new Vue({
            el:"#dataTable",
            methods:{
                deleteEmployee:function (event) {
                    //根据id获取表单元素
                    var deleteForm = document.getElementById("deleteForm");
                    //将触发点击事件的超链接的href属性赋值给表单的action
                    deleteForm.action = event.target.href;
                    //提交表单
                    deleteForm.submit();
                    //取消超链接的默认行为
                    event.preventDefault();
                }
            }
        });
    </script>
</body>
</html>

添加员工,employee_add.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>add employee</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>
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>

更新员工,employee_update.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>update employee</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>
            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="update"><br>
        </form>

    </body>
</html>

2、开放对静态资源的访问

在这里插入图片描述

我们一看,原来是没有我们写的static

在这里插入图片描述

那么我们就重新打包1下把

在这里插入图片描述

发现还是访问不了

在这里插入图片描述

defaultservlet是我们原来处理静态资源的servlet

<!-- 开放对静态资源的访问 -->
<mvc:default-servlet-handler/>

如果springMVC没有找到,就交给默认的servlet找









终于上网课了

我超,我健康码黄了😰,🏃‍♂️🏃‍♂️

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值