写点什么

SpringMVC 入门第二部分

  • 2021 年 11 月 11 日
  • 本文字数:5609 字

    阅读完需:约 18 分钟


@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



@ModelAttribute 注解



问题演示

<%@ 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 的原理








@ModelAttribute 标注在方法上面的另外一个作用







SpringMVC 确定 POJO 自定义对象值的三步




自定义类型对象的赋值流程描述,以及 @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>


![在这里插入图片描述](


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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";


}


}





请求转发地址使用相对路径







Redirect 指定重定向到页面


===============================================================================



多次重定向




@Controller


public class userController {


@RequestMapping("/hello01")


public String show()


{


return "redirect:/Fail.jsp";


}


@RequestMapping("/hello02")


public String show1()


{


return "redirect:/hello01";


}


}


注意:有前缀的转发和重定向操作,配置的视图解析器就不会进行拼串


视图解析器流程简单一句话总结原理:




jstlView 支持便捷的国际化功能—页面中英文切换



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 国际化步骤

国际化资源文件的命名规范如下:




步骤 1: 让 spring 管理国际化资源




步骤 2:直接去页面使用 fmt:message




新建两个资源文件: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>




国际化具体实现可以看下面这篇文章,链接在下面

SpringMVC国际化实现(乱码解决)idea



.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:annotation-driven/


上面这段代码,可以替代上面的那个类完成的功能,但是还需要加上注解驱动模式,不然其他依赖注解完成请求映射调整的就不好使了

开启 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/>");

评论

发布
暂无评论
SpringMVC入门第二部分