SpringMVC 入门第二部分
@SessionAttributes(types = {String.class,Integer.class})
@Controller
public class userController {
@RequestMapping("/hello")
public String show(HttpSession session, HttpServletRequest httpServlet)
{
session.setAttribute("msg1","你好 session");
httpServlet.setAttribute("msg2","你好 erquest");
return "Success";
}
@RequestMapping("/dhy")
public ModelAndView test02()
{
//之前的返回值我们就叫视图名:视图名视图解析器会帮我们最终拼串得到页面的真实地址
//ModelAndView mv=new ModelAndView("Success");
ModelAndView mv=new ModelAndView();
mv.setViewName("Success");
mv.addObject("msg","你好");
return mv;
}
}
后来推荐 @SessionAttributes 就别用了,可能会引发异常,给 session 中存放数据建议使用原生 API
问题演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>小朋友</title>
</head>
<body>
<form action="book" method="post">
价格:<input type="text" name="price"/><br>
<input type="submit" value="提交">
</form>
</body>
</html>
@Controller
public class BookController {
@RequestMapping("/book")
public String ShowBook(Book book)
{
System.out.println(book);
return "Success";
}
}
这里实际上是 springMVC 创建了一个 Book 对象,然后将对应的属性通过 set 方法赋值给该对象
如果我们要完成的操作是对数据库中保存的一条图书记录进行全更新,那么使用这种方法时,就会有问题
例如:我们在页面对图书进行修改时,无法修改图书的名字,因此 new 出来的 Book 对象的 name 值一定为 null,如果把该对象放入数据库中,那么 book 的名字就会变成 null,覆盖掉了原本图书的名字
解决方法----@ModelAttribute 的使用方式之一
如果是使用从数据库中拿出来的准备好的对象来封装请求参数,那么如果请求参数中不包括对象的全部变量值,那么剩余变量的值就依旧采用数据库中拿出来的对象自身的值,这样就不会造成为 null 的现象
@Controller
public class BookController {
@RequestMapping("/book")
//告诉 SpringMVC 不要 new 这个 book 了,而是使用我刚才保存的 book
//即用我刚才从数据库中查找出来的 book
public String ShowBook(@ModelAttribute("book") Book book)
{
System.out.println(book);
return "Success";
}
@ModelAttribute
void BookFromDao(Map<String,Object> map)
{
//模拟从数据库查出来的 book
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
map.put("book",book);
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>小朋友</title>
</head>
<body>
<form action="book" method="post">
价格:<input type="text" name="price"/><br>
<input type="submit" value="提交">
</form>
</body>
</html>
如果由 springmvc 来 New 一个新的 book 对象,那么这里的 name 就为 null
@ModelAttribute 标注在方法上面的另外一个作用
自定义类型对象的赋值流程描述,以及 @SessionAttributes 注解可能引发的异常
给自定义类型赋值,主要在于 attrName 的值,首先会把 attrName 作为 key 值去隐含模型中寻找 key==attrName 的键,然后将 key 对应的值进行赋值
举例 1:在给 Book book 对象赋值前,不加 @ModelAttribute 注解,那么会将参数类型首字母小写,即 Book—>book,去隐含模型中寻找对应的 key 值
@Controller
public class BookController {
@RequestMapping("/book")
public String ShowBook(Book book,Map<String,Object> map)
{
System.out.println(book);
return "Success";
}
@ModelAttribute
void BookFromDao(Map<String,Object> map)
{
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
map.put("book",book);//放入隐含模型中,key==book
}
}
举例 2:通过 @ModelAttribute(“haha”)来指定 attrName 的值
@Controller
public class BookController {
@RequestMapping("/book")
//告诉 SpringMVC 不要 new 这个 book 了,而是使用我刚才保存的 book
//即用我刚才从数据库中查找出来的 book
public String ShowBook(@ModelAttribute("haha") Book book,Map<String,Object> map)
{
System.out.println(book);
return "Success";
}
@ModelAttribute
void BookFromDao(Map<String,Object> map)
{
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
map.put("haha",book);//放入隐含模型中,key==haha
}
}
举例 3:attrName=haha,隐含模型中只有 key==book 的值,那么会去 session 域中寻找,@SessionAttributes(value=“haha”),但是 session 中没有键为 haha 的值,这样会报异常
@SessionAttributes("haha")
@Controller
public class BookController {
@RequestMapping("/book")
//告诉 SpringMVC 不要 new 这个 book 了,而是使用我刚才保存的 book
//即用我刚才从数据库中查找出来的 book
public String ShowBook(@ModelAttribute("haha") Book book,Map<String,Object> map)
{
System.out.println(book);
return "Success";
}
@ModelAttribute
void BookFromDao(Map<String,Object> map)
{
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
map.put("book",book);//放入隐含模型中,key==haha
}
}
举例 5:@ModelAttribute 会把方法运行后的返回值也放入隐含模型中,key 就是返回值类型小写
@Controller
public class BookController {
@RequestMapping("/book")
public String ShowBook(Book book)
{
System.out.println(book);
return "Success";
}
@ModelAttribute
Book BookFromDao()
{
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
return book;
}
}
举例 6:把返回值放入隐含模型,但是不使用默认的返回值小写作为 key,而是自己指定
@Controller
public class BookController {
@RequestMapping("/book")
public String ShowBook(@ModelAttribute("haha") Book book)
{
System.out.println(book);
return "Success";
}
@ModelAttribute("haha")
Book BookFromDao()
{
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
return book;
}
}
举例 7: 隐含模型中找不到对应的 key,session 中也找不到,那么会自动创建一个新对象
@Controller
public class BookController {
@RequestMapping("/book")
public String ShowBook(@ModelAttribute("haha") Book book)
{
System.out.println(book);
return "Success";
}
@ModelAttribute
Book BookFromDao()
{
Book book=new Book("大忽悠自传",19);
System.out.println("数据库中查到的图书信息:"+book);
return book;
}
}
@ModelAttribute 的总结
@SessionAttributes 的总结
第二点是如果隐含模型中没有,session 中就必须有,不然抛出异常
==========================================================================
注意:forward 转发到一个页面, /Fail.jsp 转发到当前项目下的 Fail.jsp. 一定要加上/,如果不加上/就是相对路径,容易出问题
forward 前缀的转发,不会由我们配置的视图解析器进行拼串
@SessionAttributes(types = {String.class,Integer.class})
@Controller
public class userController {
@RequestMapping("/hello")
public String show()
{
return "forward:/Fail.jsp";
}
}
Fail.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>失败</title>
</head>
<body>
<h1><font color="red">Lose!!!</font></h1>
</body>
</html>
![在这里插入图片描述](
https://img-blog.csdnimg.cn/20210719144045915.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUzMTU3MTcz,size_16,color_FFFFFF,t_70)
@Controller
public class userController {
@RequestMapping("/hello01")
public String show()
{
return "forward:/Fail.jsp";
}
@RequestMapping("/hello02")
public String show1()
{
return "forward:/hello01";
}
}
===============================================================================
@Controller
public class userController {
@RequestMapping("/hello01")
public String show()
{
return "redirect:/Fail.jsp";
}
@RequestMapping("/hello02")
public String show1()
{
return "redirect:/hello01";
}
}
注意:有前缀的转发和重定向操作,配置的视图解析器就不会进行拼串
视图解析器流程简单一句话总结原理:
1.导入 jstl 的依赖和 standard 的依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
2.导包如果导入了 jstl,会自动创建一个 jstlView,可以快速方便的支持国际化功能
也可以通过在 springMVC.xml 文件中配置,指定其创建 jstlView
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
回顾 javaweb 国际化步骤
国际化资源文件的命名规范如下:
新建两个资源文件:i18n_cn_CN.properties 和 i18n_un_US.properties
title=First War Of The World
zhangHao=LoginNumber
password=Password
loginBtn=Submit
title=战地 1
zhangHao=账号
password=密码
loginBtn=提交
在 springmvc 配置文件中加入 bean
springMVC.xml:
<mvc:annotation-driven />
<context:component-scan base-package="com.SpringMvc"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
<property name="defaultEncoding" value="UTF-8"/>
在 jsp 中加上标签以及替换相关需要使用的字符
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<fmt:message key="title"/>
</head>
<body>
<form action="">
<fmt:message key="zhangHao"/>: <input type="text"><br/>
<fmt:message key="password"/> :<input type="password"><br/>
<input type="submit" value='<fmt:message key="loginBtn"/>'><br/>
</form>
</body>
</html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>跳转登录页面</title>
</head>
<body>
<a href="toLoginPage" >跳转到登录页面</a>
</body>
</html>
国际化具体实现可以看下面这篇文章,链接在下面
.jsp 页面一定要过 SpringMVC 的视图解析流程,才会创建一个 jstlView 来帮你快速国际化
不能写 forward 等前缀,因为代理前缀,创建的 view 不带国际化功能
只有默认创建的 view 才有支持国际化功能
SpringMVC.xml :
<!--
发送一个请求("toLoginPage"),直接来到 web-inf 下的 login 页面,需要引入 mvc 命名空间
path=""; 指定哪个请求
view-name; 指定映射给哪个视图
走了 SpringMVC 的整个流程:视图解析....
其他的请求就不好使了,需要开启注解驱动模式
-->
<mvc:view-controller path="/toLoginPage" view-name="login"/>
上面这段代码,可以替代上面的那个类完成的功能,但是还需要加上注解驱动模式,不然其他依赖注解完成请求映射调整的就不好使了
开启 mvc 注解驱动模式,需要导入 mvc 的命名空间
1.编写自定义的视图解析器和视图实现类
自定义视图解析器需要实现视图解析器接口和 Order 接口,Order 接口是为了让自定义视图解析器先运行,否则会由默认视图解析器拦截,进行拼串
视图解析器类:
//自定义视图解析器
public class DhyViewResolver implements ViewResolver, Ordered {
private int order=0;
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
//根据视图名返回视图对象
if(viewName.startsWith("dhy:"))
{
//返回我们的一个视图解析器对象
return new MyView();
}
else
{
//该视图解析器解析不了,就返回 null,让下一个视图解析器尝试去解析
return null;
}
}
public int getOrder() {
return order;
}
//改变视图解析器的优先级
public void setOrder(int order) {
this.order = order;
}
}
视图实现类:
//自定义视图对象
public class MyView implements View {
//返回的内容数据类型
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("之前保存的数据:"+map);
//设置响应的内容类型
httpServletResponse.setContentType("text/html");
List<String> video = (List<String>) map.get("video");
for(String s:video)
{
httpServletResponse.getWriter().write(s+"<br/>");
评论