1、使用默认内置视图解析器(ViewResolver)
<!-- 默认视图解析器, 配置前缀和后缀 简化我们的开发-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" name="viewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
2、使用视图控制器
如果我们有些请求只是想跳转页面,不需要来后台处理什么逻辑,我们无法在Action中写一个空方法来跳转,直接在中配置一个如下的视图跳转控制器即可(不经过Action,直接跳转页面)
<!--视图控制器 立即访问 path:需要映射的路径 view-name:对应的文件名称-->
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="main" view-name="main" />
3、使用Model,Map,ModelMap传输数据到页面
在刚开始的helloworld项目中,我们传递了参数回到我们页面,但是后续的操作都只是接受用户的请求,那么在SpringMVC中除了可以使用原生servlet的对象传递数据之外,还有什么其他的方式呢?
package com.xixi.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@Controller
public class DTVController {
/**
* 使用Servlet API的方式传输数据到页面
**/
@RequestMapping("/servletAPI")
public String servletAPI(HttpServletRequest request){
request.setAttribute("type","servletAPI");
return "main";
}
// * 使用model的方式传输数据到页面
@RequestMapping("/model")
public String model(Model model){
System.out.println(model.getClass());
model.addAttribute("type","model");
return "main";
}
// * 使用modelMap的方式传输数据到页面
@RequestMapping("/modelMap")
public String model(ModelMap model){
System.out.println(model.getClass());
model.addAttribute("type","modelMap");
return "main";
}
// * 使用modelMap的方式传输数据到页面
@RequestMapping("/map")
public String model(Map map){
System.out.println(map.getClass());
map.put("type","map");
return "main";
}
}
model modelMap map 其实底层都是BindingAwareModelMap实现的
4.使用ModelAndView对象传输数据到页面
@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("main");
modelAndView.addObject("type","modelAndView");
return modelAndView;
}
5.使用session传输数据到页面
怎么往session设置属性?
1.通过servlet api的方式去读写session
1. 通过参数绑定的方式去获取servlet api
2.通过自动注入的方式去获取servlet api(推荐使用这种方式)
@Autowired
private HttpSession session;
/**
* 通过自动注入的方式去获取servlet api
*/
@RequestMapping("/autowired/session")
public String session02(){
session.setAttribute("type","autowired-session");
return "main";
}
通过springmvc提供的注解方式去读写session
1. @SessionAttributes
用在类上面的,写入session的。
// 从model中获取指定的属性写入session中
// 底层会从model中去找一个叫做type的属性
// 找到了会将type设置一份到session中
// 这种方式是依赖model的
// 当前控制器下所有的处理方法 都会将model指定的属性写入session
- @SessionAttribute
用在参数上面的,读取session的。 ```
- required 用来设置session中某个属性必须存在 , 不存在则会报错:HTTP Status 400 - Missing session attribute ‘type’ of type String
- model和session是互通的:session可以通过model中去获取写入指定的属性, model也会从session中自动写入指定的属性 ```
- @SessionAttributes
用在类上面的,负责写入session
@Controller
@Controller
// 通过model中指定的属性去写入到session,同时也会从session中写入指定的属性到model,
// 所以使用SessionAttributes的情况下 model和session是共同的
// 使用该方式设置session是依赖model
@SessionAttributes("type")
public class DTVController {
- @SessionAttribute
用在参数上面的,负责读取session
默认指定的属性是必须要存在的,如果不存在则会报错,可以设置required =false 不需要必须存在,不存在默认绑定null
@RequestMapping("/getSession")
public String getSession(@SessionAttribute(value="type",required = false) String type){
System.out.println(type);
return "main";
}
6、使用@ModelAttribute来获取请求中的数据常用的使用场景
常用的使用场景
1.写在方法上面
@ModelAttribute的方法会在当前处理器中所有的处理方法之前调用
1.通过@ModelAttribute来给全局变量赋值(不推荐)
2. 当我们调用执行全字段的更新数据库操作时,假如提供给用户的修改字段只有部分几个,这个时候就会造成其他字段更新丢失:
解决:
1.自己定制update语句, 只更新指定的那些字段
2.如果无法定制sql语句, 可以在更新之前进行查询, 怎么在更新之前查询?只能在springmvc 绑定请求参数之前查询, 利用@ModelAttribute就可以在参数绑定之前查询, 但是怎么将查询出来的对象和参数的对象进行合并? springmvc具有该特性, 会将model中和参数名相同的属性拿出来进行合并,将参数中的新自动进行覆盖,没有的字段进行保留。这样就可以解决这个问题。
2.写在参数上面
可以省略,加上则会从model中获取一个指定的属性和参数进行合并,因为model和sessionAttribute具有共通的特性,所以如果session中有对应的属性也会进行合并.
@ModelAttribute("user")
@ModelAttribute注解用于将方法的参数或者方法的返回值绑定到指定的模型属性上,并返回给web视图。首先来介绍一个业务场景,来帮助大家做理解,在实际工作中,有些时候我们在修改数据的时候可能只需要修改其中几个字段,而不是全部的属性字段都获取,那么当提交属性的时候,从form表单中获取的数据就有可能只包含了部分属性,此时再向数据库更新的时候,肯定会丢失属性,因为对象的封装是springmvc自动帮我们new的,所以此时需要先将从数据库获取的对象保存下来,当提交的时候不是new新的对象,而是在原来的对象上进行属性覆盖,此时就需要使用@ModelAttribute注解。
总结:通过刚刚的给参数赋值,大家应该能够发现,当给方法中的参数设置值的时候,如果添加了@ModelAttribute注解,那么在查找值的时候,是遵循以下方式:
1、方法的参数使用参数的类型首字母小写,或者使用@ModelAttribute(“”)的值
2、先看之前是否在model中设置过该属性值,如果设置过就直接获取
3、看@SessionAttributes注解标注类中的方法是否给session中赋值,如果有的话,也是直接获取,没有报异常
3种方式的获取servlet—api的线程安全问题:
线程不安全=并发问题: 同一个时间,多个线程,同时对共享数据/变量/资源 进行读写操作,就会产生并发问题(脏读、幻影读…)
1.通过参数绑定的方式
是线程安全的,因为参数绑定的方式变量是方法级别的,所以每次请求方法都会在内存中开辟自己独立的空间。
2.通过@AutoWired自动注入的方式
是线程安全的,特殊,虽然他是共享变量(单例类级别的变量),但是springmvc底层 通过ThreadLocal来存储的servlet api,所以通过自动注入进来的servlet api是线程安全的。
3.通过@ModelAtrribute的方式
不是线程安全的,因为他是共享变量
7.使用forward实现页面转发
//1。默认就是转发
//2。可以显示加上forward进行转发,foward需要自己加上返回的完整视图逻辑名和路径,因为不会参与走视图解析器的解析
@RequestMapping("/foward/test")
public String forward(){
return "forward:/login.jsp";
}
//重定向
//必须加上redirect,不会参与走视图解析器的解析
//注意:/会包含项目名称 springmvc 碰到redirect 自动会加上项目名称,Servlet要加上项目名称
@RequestMapping("/redirect/test")
public String redirect(){
return "redirect:/login.jsp";
}