Spring MVC 学习日志3.响应处理(使用IDEA)

1、配置视图解析器

    <!--默认视图解析器 -   配上前缀和后缀 简化视图逻辑名称-->
    <bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver" name="viewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

2、配置视图控制器,直接访问

    <!--视图控制器 立即访问,配置之后就不需要在controller里面加处理方法-->
    <mvc:view-controller path="/" view-name="index"/>
    <mvc:view-controller path="/main" view-name="main"/>

3、传输数据到页面

   3.1、使用Model、Map、ModelMap、ModelAndView传输数据

   3.2、获取session的几种方式

       3.2.1. 通过参数绑定的方式去获取servlet api
       3.2.2.通过自动注入的方式去获取servlet api(推荐使用这种方式

       3.2.3.通过springmvc提供的注解@SessionAttributes、@SessionAttribute去读写session

  3.3、使用@ModelAttribute注解来获取请求中的数据

  ·应用场景

*  一、写在方法上
*      1.通过@ModelAttribute来给全局变量赋值;设置servlet api--session(不推荐)
*      2. 当我们调用执行全字段的更新数据库操作时,假如提供给用户的修改字段只有
*      部分几个,这个时候就会造成其他字段更新丢失:
*          解决:
*              1.自己定制update语句,只更新指定的那些字段
*              2.如果无法定制sql语句,可以在更新之前进行查询,怎么在更新之前查询?只
*              能在springmvc 绑定请求参数之前查询,利用@ModelAttribute就可以在参数绑定之前
*              查询, 但是怎么将查询出来的对象和参数的对象进行合并?springmvc具有该特性,会
*              将model中和参数名相同的属性拿出来进行合并,将参数中的新字段进行覆盖,没有的字段
*              进行保留。这样就可以解决这个问题。
*  二、写在参数上
*      可以省略,加上则会从model中获取一个指定的属性和参数进行合并,因为model和
*      sessionAttribute具有共通的特性,所以如果session中有对应的属性也会进行合并

  3.4、3种获取servlet-api的方式线程安全问题(并发问题)

*  3种方式获取servlet-api的线程安全问题(并发问题)
*   线程不安全=有并发问题:同一个时间,多个线程,同时对数据/变量/资源进行读写操作
*   就会产生并发问题(脏读、幻读)
*   共享变量:只在内存中创建一次(static),单例中定义在类里的变量
*           1.并行变串行
*          2 .将变量变为非共享,声明在方法中或创建在ThreadLocal中
*  1.听过参数绑定方式
*      是线程安全的,因为该方式下变量是方法级别的,所以每次请求,处理方法都会在内存中开辟自己独立的空间
*  2.通过@Autowired自动注入的方式
*      是线程安全的,很特殊,虽然他是共享变量(单例类内级别变量),但是在springmvc底层是使用的ThreadLocal存储的
*      servletapi,因此通过自动注入进来的servletapi是线程安全的
*  3.通过@ModelAtrribute的方式(全局变量的方式)(根源通过参数绑定,区别在于赋值到类内变量级别)
*      不是线程安全的,虽然session是通过参数绑定,但是之后赋值给了共享变量(单例类内级别变量)
*      springmvc是否单例,有线程安全吗?怎么解决?
*      是单例的。按照常规来说,不会有线程安全问题,因位springmvc都是方法级别的问题。

  3.5、 SendDataToViewController

package cn.tulingxueyuan.controllers;

import cn.tulingxueyuan.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;

@Controller
//使用springmvc自动注解的方式
// 1.写在类前,要利用model,从model中拷贝一份"type"的值
// 即从model(model,modelmap,map,modelandview)中获取指定的属性写入session中
//底层会从model中找一个叫做type的属性找到了会将type拷贝一份到session中
//这种方式是依赖model的
//当前控制器下所有的处理方法,都会讲指定的model属性写入session
@SessionAttributes("type")

public class SendDataToViewController {
    /**
     *  使用servlet 原生API 的方式传输数据到View视图
     * @param request
     * @return
     */
    @RequestMapping("/servletAPI")
    public String servletAPI(HttpServletRequest request){
        request.setAttribute("type","servletAPI");
        return "main";
    }

    /**
     * 使用model的方式传输数据到View视图
     * @param model
     * @return
     * 底层还是requset实现
     */
    @RequestMapping("/model")
    public String model(Model model){
        System.out.println(model.getClass());
        model.addAttribute("type","model");

        return "main";
    }

    /**
     * 使用modelmap的方式传输数据到View视图
     * @param modelMap
     * @return
     */
    @RequestMapping("/modelmap")
    public String modelmap(ModelMap modelMap){
        System.out.println(modelMap.getClass());
        modelMap.addAttribute("type","modelmap");
        return "main";
    }
    /**
     * 使用map的方式传输数据到View视图
     * @return
     */
    @RequestMapping("/map")
    public String map(Map map){
        System.out.println(map.getClass());
        map.put("type","map");
        return "main";
    }

    @RequestMapping("/mav")
    public ModelAndView mav(){
        ModelAndView mv = new ModelAndView("main");
//        mv.setViewName;
        mv.addObject("type","ModelAndView");
        return mv;
    }

    /**
     *  通过参数绑定的方式获取servlet api---session
     */
    @RequestMapping("/servletapi/session")
    public String session01(HttpSession session){
        session.setAttribute("type","servletapi-session");
        return "main";
    }

    /**
     *  通过自动注入的方式获取servlet api---session(*****建议使用 )
     *  推荐这种
     */
    @Autowired
    private HttpSession session;
    @RequestMapping("/autowired/session")
    public String session02(){
        session.setAttribute("type","autowiredsession");
        return "main";
    }

    /**
     *
     * @SessionAttribute 获取session
     * 属性required 用来设置session中某个属性必须存在,不存在则报错
     * model和session是互通的:session可以通过model去获取然后写入的指定属性,model也会从session中自动获取并写入指定属性
     *
     * @param type
     * @return
     */
    @RequestMapping("/annotation/session")
    public String session03(@SessionAttribute(value = "type", required = false) String type, Model model){
        System.out.println(type);
//        model.addAttribute("type",type);
        return "main";
    }

    /**
     * 所有处理方法被调用前,都会先调用注解@ModelAttribute下面的showModelAttribute方法
     * 应用场景:
     *  一、写在方法上
     *      1.通过@ModelAttribute来给全局变量赋值;设置servlet api--session(不推荐)
     *      2. 当我们调用执行全字段的更新数据库操作时,假如提供给用户的修改字段只有
     *      部分几个,这个时候就会造成其他字段更新丢失:
     *          解决:
     *              1.自己定制update语句,只更新指定的那些字段
     *              2.如果无法定制sql语句,可以在更新之前进行查询,怎么在更新之前查询?只
     *              能在springmvc 绑定请求参数之前查询,利用@ModelAttribute就可以在参数绑定之前
     *              查询, 但是怎么将查询出来的对象和参数的对象进行合并?springmvc具有该特性,会
     *              将model中和参数名相同的属性拿出来进行合并,将参数中的新字段进行覆盖,没有的字段
     *              进行保留。这样就可以解决这个问题。
     *  二、写在参数上
     *      可以省略,加上则会从model中获取一个指定的属性和参数进行合并,因为model和
     *      sessionAttribute具有共通的特性,所以如果session中有对应的属性也会进行合并
     */
    @RequestMapping("/modelattribute/session")
    public String session04(){
        session2.setAttribute("type","ModelAttribute-session");
        return "main";
    }


    /*
    此例子不明显,因为sessionid的缘故,一个线程的session被覆盖后,就找不到了
    @RequestMapping("/thread/test")
    public String session05(String name) throws InterruptedException {
        Thread.sleep(5000);
        session2.setAttribute("type",name);
        return "main";
    }*/
    //String username;这样会产生线程安全问题,因为会对共享变量同时进行读写操作
    @RequestMapping("/thread/test")
    public String session05(String name, HttpServletRequest request) throws InterruptedException {
        //声明在方法中,可以解决共享变量产生的线程安全问题
        String username=name;
        Thread.sleep(5000);
        request.setAttribute("type",username);
        return "main";
    }
    /**
     * 通过 @ModelAttribute来获取servlet api--session并赋值
     *
     */

    HttpSession session2;
    @ModelAttribute
    public  void  showModelAttribute(HttpSession session){
        this.session2=session;
        System.out.println("ModelAttribute-----------");
    }

    /**
     * 解决问题,修改username会把password变为null
     *
     * @param model
     */
/*    @ModelAttribute
    public  void  initUser(Model model){
        //从数据库中查询User  select * from user
        //假设该user是从数据库查询出来的
        User user = new User();
        user.setId(1); user.setUsername("qqa"); user.setPassword("13234");
        model.addAttribute("user",user);
    }*/

    /**
     * springmvc在进行参数绑定前,会将model中跟参数名符合的属性拿出来合并
     * 参数中新提交的字段会覆盖,缺失的字段会保留
     *
     * @param user
     * @return
     */
    @RequestMapping("/update")
    public String update(@ModelAttribute("user") User user){

        //update user set id=?,username=?,password=?  where id=?
        //这种全字段更新会把password设置为null
        System.out.println(user);
        return "main";
    }
    /*
    @ModelAttribute
    public  void  showModelAttribute(){
        System.out.println("ModelAttribute-----------");
    }*/
    /**
     *  3种方式获取servlet-api的线程安全问题(并发问题)
     *   线程不安全=有并发问题:同一个时间,多个线程,同时对数据/变量/资源进行读写操作
     *   就会产生并发问题(脏读、幻读)
     *   共享变量:只在内存中创建一次(static),单例中定义在类里的变量
     *           1.并行变串行
     *          2 .将变量变为非共享,声明在方法中或创建在ThreadLocal中
     *  1.听过参数绑定方式
     *      是线程安全的,因为该方式下变量是方法级别的,所以每次请求,处理方法都会在内存中开辟自己独立的空间
     *  2.通过@Autowired自动注入的方式
     *      是线程安全的,很特殊,虽然他是共享变量(单例类内级别变量),但是在springmvc底层是使用的ThreadLocal存储的
     *      servletapi,因此通过自动注入进来的servletapi是线程安全的
     *  3.通过@ModelAtrribute的方式(全局变量的方式)(根源通过参数绑定,区别在于赋值到类内变量级别)
     *      不是线程安全的,虽然session是通过参数绑定,但是之后赋值给了共享变量(单例类内级别变量)
     *      springmvc是否单例,有线程安全吗?怎么解决?
     *      是单例的。按照常规来说,不会有线程安全问题,因位springmvc都是方法级别的问题。
     */

}

4、转发与重定向的区别

  4.1转发:

    由服务器的页面进行跳转,不需要客户端重新发送请求:
    特点如下:
    1、地址栏的请求不会发生变化,显示的还是第一次请求的地址
    2、请求的次数,有且仅有一次请求
    3、请求域中的数据不会丢失
    4、根目录:localhost:8080/项目地址/,包含了项目的访问地址

  4.2重定向:
    在浏览器端进行页面的跳转,需要发送两次请求(第一次是人为的,
   第二次是自动的)
    特点如下:
    1、地址栏的地址发生变化,显示最新发送请求的地址
    2、请求次数:2次
    3、请求域中的数据会丢失,因为是不同的请求
    4、根目录:localhost:8080/  不包含项目的名称

package cn.tulingxueyuan.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ResponseController {

    @RequestMapping("/response01")
    public String response01() {
        return "index";
    }

    /**
     * 转发的实现
     *  1.默认就是进行转发,并且会进行视图解析
     *  2.可以显式的加上forward进行转发,forward需要自己返回完整视图逻辑逻辑名和路径,因为不会进行ViewResolver的解析
     *  与重定向不同:
     *      1.地址栏不会改变
     *      2.由服务器实现页面跳转
     *      3.知道项目的地址,不用自己写
     *      4.request域不会丢失
     *      5.一次请求
     * @return
     */
    @RequestMapping("/response02")
    public String response02() {
        //return "index";
        //使用这种方式时,视图解析器会失效,不会自动加前后缀,但是知道项目地址,所以不用加
        return "forward:/login.jsp";
    }

    /**
     *  重定向
     *  必须加上"redirect"的关键字
     *      注意:/会包含项目名,springmvc特殊之处,识别到"redirect"的关键字后,会在底层自动加上项目地址
     *  但是,servlet一定要加上项目名
     *
     *  与转发不同:
     *      1.地址栏会改变
     *      2.由客户端实现页面跳转
     *      3.不知道项目的地址,需要自己写
     *      4.request域会丢失
     *      5.两次请求
     */
    @RequestMapping("/response03")
    public String response03() {
        return "redirect:/login.jsp";
        //这种写法不行,因为WEB-INF中数据 访问受限
        // return "redirect:/WEB-INF/views/index.jsp";
    }
}

5、main.jsp

<%--
  Created by IntelliJ IDEA.
  User: lenovo
  Date: 2021/3/10
  Time: 19:02
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>TestTitle</title>
</head>
<%--<% String res=request.getAttribute("type").toString(); %>--%>
<body>
    test:${requestScope.type}<p></p>
    get type from session :${sessionScope.type}<p/>
    User:${requestScope.user}
</body>
</html>

6、User bean

package cn.tulingxueyuan.entity;

public class User {
    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值