SpringMVC-Day1 (课题有用)
第一章:三层架构和MVC
SpringMVC是表现层的框架。
1. MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
2. Model:数据模型,JavaBean的类,用来进行数据封装。
3. View:指JSP、HTML用来展示数据给用户
4. Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等
工作流程:
浏览器向服务器发送请求——>控制器接收请求——>用javabean将数据封装起来——>与业务层交互
从业务层获得了返回的数据——>将数据封装至javabean——>程序转发至JSP,并显示结果,生成html——>响应给浏览器
第二章:SpringMVC的入门案例(重要)
1. SpringMVC的概述(查看大纲文档)
1. SpringMVC的概述
1). 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。
2). Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供 了构建 Web 应用程序的全功能 MVC 模块。
3). 使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的 SpringMVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2(原来是表现层啊)等。
2. SpringMVC在三层架构中的位置
1). 表现层框架
3. SpringMVC的优势:模块化
4. SpringMVC和Struts2框架的对比(面试背下来)
2. SpringMVC的入门程序(重要)
1. 先创Spring_MVC空包。
创建WEB工程模块,maven的使用骨架,选择maven-archetype-webapp,新建spring_day01_01_start
到这一步会默认去网上下载插件很费时间(当时我fq才解决),我们点加号添加这一组键值对。(干啥的???
(下面这个别用了!!!!!直接点next!!!!!
并没很快。。。而且还往c盘里下载了一大堆啥玩意?可怕。。。下载了两分钟。。(别用了!!!!!直接点next!!!!!
2.把目录补全
3.引入开发的jar包,具体的坐标如下
又开始了...每次入门为何都如此艰辛。。。
是有什么毛病吗 dependencies好不容易都导入了 plugins又报红???
大概是阿里云仓库没有这个2.8.2吧 碰巧web老师资料里有 复制粘贴到本地仓库,reimport解决了。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xxw</groupId> <artifactId>springmvc_day01_01_start</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>springmvc_day01_01_start Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <!--这是版本控制配置 后面dependencies们用el表达式引用它--> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>springmvc_day01_01_start</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
4.在web.xml里面配置servlet,叫前端控制器?(想念tomcat用注解配置多方便啊。。。)(啊啊啊其实这里其他的controller们也是的用reqMapping注解写在类上就可以对应url找到这个类,只是这个前端控制器是mvc框架的不是自己写的servlet!!!怎么我吐的槽都会被打脸)
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!--配置前端控制器 必须是这个class(dispatcher分发器?java300集的手写服务器项目见过)--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
5.res下面新建一个springmvc.xml文件(干啥?。。spring的配置文件,这样建的自动有头信息 啊!这个就是之前的bean.xml
6.然后部署服务器,感谢弹幕提示到run里面edit里面+tomcat...把项目弄进来
以上就是环境搭建。
开始写入门程序,发送一个请求给后台程序,后台能够接收到该请求并且执行对应的业务方法,输出一段话。并且返回一个成功的页面。
写一个controller在里面用到了@RequestMapping注解。
然后配置springmvc.xml使可以扫描包用注解,但是还得在web.xml的前端控制器里面配置加载springmvc.xml的代码。。。(之前的bean.xml是谁加载classpath的来着?好像并不需要。)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 开启注解扫描 --> <context:component-scan base-package="com.xxw"/> <!-- 视图解析器对象 id是固定的 根据cotroller它return的名字跳转去找jsp--> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 开启SpringMVC框架注解的支持 --> <mvc:annotation-driven conversion-service="conversionService"/> </beans>
入门报错:
严重 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.startup.ContextConfig.beforeStart Exception fixing docBase for context [/day01_01]
java.io.IOException: Unable to create the directory [D:\LenovoQMDownload\tomcat\apache-tomcat-8.5.31\webapps\day01_01]
查遍帖子都没有我这种IOException 无奈新建一个javaee模块看一看是不是版本问题之类的。最后发现是部署问题,跟着老师部署war结尾的不可以,我得移除war添加用war exploded结尾的(这个是新建ee模块发现的。并不知道为什么。。。)
查了一下也没太看明白:https://blog.csdn.net/xlgen157387/article/details/56498938
其实还有一个疑问:老师jre用的路径,但ee项目显示默认的(同学说就用默认的不用跟老师一样!!!!
再运行成功出现了index.jsp里写的页面
但是点击超链接又出错了。。。。并没有跳转到success.jsp而是500了。。。狗生艰难。。。。。。。。
网页报错:500
Type Exception Report
Message Servlet.init() for servlet [dispatcherServlet] threw exception
Description The server encountered an unexpected condition that prevented it from fulfilling the request.
Exception
javax.servlet.ServletException: Servlet.init() for servlet [dispatcherServlet] threw exception
Root Cause
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping':
Initialization of bean failed;
绝望 按exception和root cause找遍互联网也没结果。浪费狗生一天。。。。
--------------------------------------------------------------------------------------------------------------
重来一遍,让苍天知道,我不认输。。。
放弃视频,按这个帖子来入门https://www.cnblogs.com/wmyskxz/p/8848461.html
完了我照着帖子选的springmvc4.3.18 但是自动下载的别的jdbc,tx啥的都是5.2.3版本的??希望没事。。。
不知道跳出个啥下载失败我选了个try again...try agin也没用我去。。。我的老天鹅啊为什么要这么对我
苍天对不起,我认输。。。
----------------------------------------------------------------------------------------------------------------
吸杯奶茶 我还能站起来。。。。问了同学们她们都是跟视频成功通过了没用键值对。。。。
好,那我再再跟视频重新来一次。这次要再不行就fq下载上面的模板建工程。
心平气和,心平气和,心平气和。。。。
---------------------------------------------------------------------------------------------------------------------------------------------
新建模块start2,用webapp模板,这次不用那个键值对,然后复制了老师的代码工程。
tomcat那个jre是默认,content还是/day01,部署那个war有exploded后缀的模块
感天动地运行成功了!!!!!!!!生活终于对我这只可怜的小猫咪露出了微笑。。(但是并不知道之前为啥是500?代码才那么几行不可能敲错啊。是那个诡异的键值对的问题??????
--------------------------------------------------------------------------------------------------------
ok...几经辗转......终于回到视频学习上.......
我们入门的过程:
1. 入门案例的执行流程
1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签(在web.xml里面),所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
2. 开启了注解扫描,那么HelloController对象就会被创建
3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法
4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
5. Tomcat服务器渲染页面,做出响应
(我之前就是从DispacherServlet就开始不作为!!!!报错!!!不识别!!!死活不去加载springmvc.xml!!!想想就气!!!为啥啊!!!明明一模一样的代码?web.xml也配置了啊!!!难道就是那个键值对模板导致????)
请求协议----->前端控制器DispatcherServlet------>处理器映射器HandlerMapping----->前端控制器DispatcherServlet----->处理器适配器HandlerAdapter
----->前端控制器DispatcherServlet------>视图解析器ViewResolver------->前端控制器DispatcherServlet------->1.视图渲染,将数据填充;2.发送响应协议
(适配器具体是适配啥呢??
2.4 RequestMapping 注解
见pdf上,懒得写了
代码:
// 控制器类 @Controller @RequestMapping(path="/user") public class HelloController { /** * 入门案例 * @return */ //这个注解与方法建立映射关联的url 方法上的是二级目录 类上就是一级 类上写了以后,再方法就得先加类的url @RequestMapping(path="/hello") public String sayHello(){ System.out.println("Hello StringMVC"); return "success";//这里返回写的字符串 根据视图解析器自动跳转到对应的jsp视图 } /** * RequestMapping注解 * @return */ @RequestMapping(value="/testRequestMapping",params = {"username=heihei"},headers = {"Accept"}) public String testRequestMapping(){ System.out.println("测试RequestMapping注解..."); return "success"; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h3>入门程序</h3> <%--测试跳转到HelloController上的requestMapping--%> <%--<a href="hello">入门程序 req在方法上注解</a>--%> <%--<a href="/user/testRequestMapping">入门程序 req加上了类注解</a>--%> <a href="user/testRequestMapping?username=heihei">RequestMapping注解另一个方法上加了parm等属性</a> </body> </html>
运行结果:就是运行tomcat出来首页,点击首页的超链接跳到HelloController里匹配到对应url的方法执行,结果是控制台输出,然后方法里面还有根据适配器和视图解析器把对应的jsp页面输出。
第三章:请求参数的绑定(重要)
1. 请求参数的绑定说明
1. 绑定机制
1. 表单提交的数据都是k=v格式的 username=haha&password=123
2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
3. 要求:提交表单的name和参数的名称是相同的!!!
2. 支持的数据类型
1. 基本数据类型和字符串类型
2. 实体类型(JavaBean)
3. 集合数据类型(List、map集合等)
2. 基本数据类型和字符串类型
1. 提交表单的name和参数的名称是相同的
2. 区分大小写
3. 实体类型(JavaBean)
1. 提交表单的name和JavaBean中的属性名称需要一致
2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
代码:
(1)首先要定义一个实体类javabean
(2)param.jsp中写一个表单!上传实体类属性们的数据,请求参数名称要和实体类对上!!
<%--把数据封装Account类中 搞一个表单,用表单提交请求参数的数据!!!name要跟javabean的属性名相同!!! (xxw的Data表则是Data类!但是这非得靠表单 我那实时传感器数据如何自动填充到表单提交到服务器呢?我每走一步触发获取传感器数据提交到服务器封装成对象 总之不是type=text手动输入上传到服务器。 这里这个action靠二级目录直接指向方法,课题就很有用!!!!)--%> <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> <input type="submit" value="提交" /> </form>
(3)根据action里的二级url直接指向servlet里面的方法!mvc可以把数据们封装到方法的javabean参数里面输出或保存!(课题应该是拿出计算的模值保存到list,这么想好像不用封装到bean...? aaa我其实可以考虑mysql数据库换为sqlite啊啊啊啊离线也可以用!!!!)
/** * 请求参数绑定把数据封装到JavaBean的类中 * @return */ @RequestMapping("/saveAccount") public String saveAccount(Account account){//springmvc会自动把请求参数数据们填充到方法参数javabean对象里面 System.out.println("执行了..."); System.out.println(account); return "success"; }
这个很有用啊啊啊啊啊!!!!!课题可以用。
运行结果:在浏览器中输入http://localhost:8080/day01/param.jsp 进入表单提交页面
输入数据
提交后,控制台方法成功输出了接收到表单数据们的实体类对象,然后跳转到了success.jsp页面
执行了...
Account{username='zhangsan', password='1007', money=1007.0}
若实体类里包含引用类型(别的实体类对象作为属性!!!)
实体类除了增加引用类型和其set,get方法外,toString方法也要记得改,不然控制台打印实体类对象时打不出引用类型
jsp的表单这样写,也跟其他属性一样
<form action="param/saveAccount" method="post">
姓名:<input type="text" name="username" /><br/>
密码:<input type="text" name="password" /><br/>
金额:<input type="text" name="money" /><br/>
用户姓名:<input type="text" name="user.uname" /><br/>
用户年龄:<input type="text" name="user.age" /><br/>
<input type="submit" value="提交" />
</form>
运行结果:
提交后控制台输出:
执行了...
Account{username='zhangsan', password='1007', money=1007.0, user=User{uname='zhangsan', age=28}}
页面跳转到success.jsp
4. 给集合属性数据封装
若实体类里包含集合!!
private List<User> list;
private Map<String,User> map;
1. JSP页面编写方式:list[0].属性
<%--把数据封装Account类中,类中存在list和map的集合 --%> <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> <%--user对象泛型的数据们存到list集合的0号位上--%> 用户姓名:<input type="text" name="list[0].uname" /><br/> 用户年龄:<input type="text" name="list[0].age" /><br/> <%--String泛型的key,user对象泛型的value数据们存到map集合的对应的key上--%> 用户姓名:<input type="text" name="map['one'].uname" /><br/> 用户年龄:<input type="text" name="map['one'].age" /><br/> <input type="submit" value="提交" /> </form>
controller不变,依然打印对象
运行结果:
执行了...
Account{username='张艺兴', password='1007', money=1007.0, user=null, list=[User{uname='罗志祥', age=20}], map={one=User{uname='黄磊', age=21}}}
成功打印出list和map的tostring!!(忘记把引用类型注释掉了)
5. 请求参数中文乱码的解决
执行了...
Account{username='??????', post请求到服务器拿数据后,控制台输出乱码的中文名
1. 在web.xml中配置Spring提供的过滤器类
<!--配置解决中文乱码的过滤器--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
6. 自定义类型转换器
1. 表单提交的任何数据类型全部都是字符串类型,但是后台定义参数为Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。
若实体类User有一个Date类型的属性,jsp表单对应cotroller里的saveUser方法
jsp:
<%--自定义类型转换器 表单--%> <form action="param/saveUser" method="post"> 用户姓名:<input type="text" name="uname" /><br/> 用户年龄:<input type="text" name="age" /><br/> 用户生日:<input type="text" name="date" /><br/> <input type="submit" value="提交" /> </form>
controller:
/** * 自定义类型转换器 * @param user * @return */ @RequestMapping("/saveUser") public String saveUser(User user){ System.out.println("执行了..."); System.out.println(user); return "success"; }
运行结果:
jsp输入
然后报错了。。。
但是jsp输入
成功了。。。
WHY????不服就自定义格式!
2. 如果想自定义数据类型转换,可以实现Converter的接口
1). 自定义类型转换器
2). 注册自定义类型转换器,在springmvc.xml配置文件中编写配置
1).新建一个utils包StringToDateConverter类,实现Converter接口
/** * 把字符串转换日期 */ public class StringToDateConverter implements Converter<String,Date>{ /** * String source 传入进来字符串 * @param source * @return */ @Override public Date convert(String source) { // 判断 if(source == null){ throw new RuntimeException("请您传入数据"); } DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); try { // 把按格式的字符串转换为日期 Date date = df.parse(source); return date; } catch (Exception e) { throw new RuntimeException("数据类型转换出现错误"); } } }
2).在springmvc.config配置这个类为自定义类型转换器
<!--配置自定义类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.itcast.utils.StringToDateConverter"/> </set> </property> </bean> <!-- 开启SpringMVC框架注解的支持 默认配上了映射器,适配器,解析器 后面加上自定义的组件:自定义类型转换器--> <mvc:annotation-driven conversion-service="conversionService"/>
.................我好像知道我之前入门为啥出错了。。。。复制这一句开启框架支持的语句,不小心把还没写的这个自定义类的配置复制进去了。。难怪前端控制器不肯去读配置文件直接罢工,因为配置文件出错了啊!!!!!!!!!。。。。。。。。。wtf..........又是被自己蠢哭的一天.............................................
运行结果:2020-10-07可以提交跳转到成功,变成2020/10/07不可以了
7. 在控制器中使用原生的ServletAPI对象
1. 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象,然后就可以直接获得对象们了
/** * 原生的API * @return */ @RequestMapping("/testServlet") public String testServlet(HttpServletRequest request, HttpServletResponse response){ //然后这里面可以像之前的servlet的doGet方法里面那样写业务逻辑 System.out.println("执行了..."); System.out.println(request); HttpSession session = request.getSession(); System.out.println(session); ServletContext servletContext = session.getServletContext(); System.out.println(servletContext); System.out.println(response); return "success"; } }
jsp写个超链接测试:
<a href="param/testServlet">Servlet原生的API</a>
运行结果就是控制台输出对象们的地址
----------------------------------------------------------------------------------------------------
这里是由reqMapping直至方法。web时代的servlet咋用方法来着?req get参数 然后干啥来着?复习一下
emmmmmm一复习才知道原来之前就学过用把数据们封装到对象啊,还学过两种方式封装(一种获取后调用set方法,一种用BeanUtils这个jar包,如下代码),我怎么像失忆了的nt。。。只是没这里方法的方便,mvc直接对应好了对象作为参数就行...
然后servlet里都是在doPost方法或doGet里面写业务逻辑一步一步往下写,没有像这里这样可以分成各种方法按二级url找方法
之前的web写servlet的业务是这样的:
//完成具体登录业务 @WebServlet(“/LoginServlet”) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request,response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //完成具体逻辑 //1.设置编码 request.setCharacterEncoding(“utf-8”); /* //2.获取请求参数 String username = request.getParameter(“username”); String password = request.getParameter(“password”); //3.封装User对象 User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password);*/ /**这次使用BeanUtils完成请求参数set到用户loginUser对象里面 * 2.获取所有请求参数*/ Map<String, String[]> map = request.getParameterMap(); /**3.创建User对象*/ User loginUser = new User(); /**3.2使用BeanUtils封装,用populate方法完成Map到Bean里面*/ try { BeanUtils.populate(loginUser,map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } //4.调用UserDao的login方法 UserDao dao = new UserDao(); User user = dao.login(loginUser); //5.判断user if(user == null) { //登录跳转 转发共享 //登录失败 request.getRequestDispatcher(“/FailServlet”).forward(request, response); }else { //登录成功 转发时还要存储数据 request.setAttribute(“user”,user); request.getRequestDispatcher(“/SuccessServlet”).forward(request, response); } } }
想起之前300集手写服务器的项目。。。简直远古时代。。。
-----------------------------------------------------------------------------------------------------
第四章:常用的注解
新建anno.jsp 新建AnnoController
1. RequestParam注解
1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值。(主要是解决了请求参数与controller的形参的名字不一样时无法把数据自动教给形参的问题)
2. 属性
1). value:请求参数中的名称
2). required:请求参数中是否必须提供此参数,默认值是true,必须提供
3. 代码如下
jsp中请求参数名是myname,controller中形参名为username,@requestParam这样用 写形参前面。加了以后jsp的请求参数必须是myname了就,username都不行
@RequestMapping("/testRequestParam") public String testRequestParam(@RequestParam(value="myname") String username){ System.out.println("执行了..."); System.out.println(username); return "success"; }
jsp:
<a href="anno/testRequestParam?myname=哈哈">RequestParam</a>
运行结果就控制台成功打印出了哈哈,jsp跳转到success.jsp
2. RequestBody注解
1. 作用:用于获取请求体的内容(注意:get方法不可以所以不可以用超链接,post才有请求体,异步json会用!!!拿请求体中key value)
2. 属性
1). required:是否必须有请求体,默认值是true
3. 用法代码如下
jsp表单 post提交:
<form action="anno/testRequestBody" method="post"> 用户姓名:<input type="text" name="username" /><br/> 用户年龄:<input type="text" name="age" /><br/> <input type="submit" value="提交" /> </form>
AnnoController中写方法:
/** * 获取到请求体的内容 * @return */ @RequestMapping("/testRequestBody") public String testRequestBody(@RequestBody String body){//注意这儿的参数不再是username或是user对象拿数据 加上注解代表想拿请求体 System.out.println("执行了..."); System.out.println(body); return "success"; }
运行结果:
地址栏输入anno.jsp
提交后控制台输出请求体!!!
执行了...
username=zhangsan&age=18
3. PathVariable注解
1. 作用:绑定url中的占位符。例如:url中有/delete/{id},{id}就是占位符(则请求路径要写/delete/10)
2. 属性
1). value:指定url中的占位符名称
3. Restful风格的URL(重要!!!!怎么像300集用过的那个火狐插件的名字。。。
1). 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
2). restful风格的URL优点 :1. 结构清晰 2. 符合标准 3. 易于理解 4. 扩展方便
可以和后面的ajax,axios完美契合 实际开发很有用
4. 用法代码如下
controller:
/** * PathVariable注解 * @return */ @RequestMapping(value="/testPathVariable/{sid}") public String testPathVariable(@PathVariable(value="sid") String id){//这里和@RequestPrama一样诶 形参不必非为sid了??
//不过jsp根本都没写参数名直接上值10
System.out.println("执行了..."); System.out.println(id); return "success"; }
jsp:
<a href="anno/testPathVariable/10">testPathVariable</a>
运行结果:(区别是这里直接输出10而不是前面基本数据类型那里的id='10'!!这里不用管参数名key直接拿值!!课题传参好像可以直接这样啊!!!)
执行了...
10
4. RequestHeader注解
1. 作用:获取指定请求头的值
2. 属性
1). value:请求头的名称
3. 代码如下 不写了太简单了不重要
运行结果:(打印头信息)
执行了...
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
5. CookieValue注解
1. 作用:用于获取指定cookie的名称的值(浏览器端存了cookie,服务器想要获取值的话用该注解)
2. 属性
1). value:cookie的名称
3. 代码
<a href="anno/testCookieValue">CookieValue</a>
/** * 获取Cookie的值 * @return */ @RequestMapping(value="/testCookieValue") public String testCookieValue(@CookieValue(value="JSESSIONID") String cookieValue){ System.out.println("执行了..."); System.out.println(cookieValue); return "success"; }
运行结果:
执行了...
336ED963568F1A16641D249B6A53257C
6. ModelAttribute注解
1. 作用
1. 出现在方法上:表示当前方法会在控制器方法执行前执行。(只要给一个方法在方法上边写了这个@ModelAttribute注解,这个方法就会在任意其他方法前先执行一次。跟那个junit的@before一样。。。)
2. 出现在参数上:获取指定的数据给参数赋值。
2. 应用场景
1. 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据,而不是变成null。
3. 具体的代码(得用上User实体类,请求参数名称要对上属性名称)
jsp:写一个表单,只提交user类的uname和age,date不提交。则按mvc的自动参数绑定date那儿会是一个null。
<form action="anno/testModelAttribute" method="post"> 用户姓名:<input type="text" name="uname" /><br/> 用户年龄:<input type="text" name="age" /><br/> <input type="submit" value="提交" /> </form>
cotroller:
1. 修饰的方法有返回值(User)
/** * ModelAttribute注解 * @return */ @RequestMapping(value="/testModelAttribute") public String testModelAttribute(User user){ System.out.println("testModelAttribute执行了..."); System.out.println(user); return "success"; } /** * 该方法会先执行 */ @ModelAttribute public User showUser(String uname,int age) throws ParseException { System.out.println("showUser执行了..."); // 通过用户查询数据库(模拟) User user = new User(); System.out.println(uname+"+"+age);//输出了请求参数的数据们!!!神奇!这里也可以自动对应上类型!! user.setUname(uname);//同请求参数输入的数据 没改 user.setAge(20);//手动改了!!但因为后面只拿表格里的所以并没有影响后面
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
user.setDate(df.parse("2020-05-14"));//手动改了!!因为表格里没有这一项所以后面继承了这里改的!!
System.out.println(user); return user; }
运行结果:
表单提交
控制台输出:
showUser执行了...
joker+18
User{uname='joker', age=20, date=Thu May 14 00:00:00 CST 2020}
testModelAttribute执行了...
User{uname='joker', age=18, date=Thu May 14 00:00:00 CST 2020}
可以看出,提交的依然都保存住了没有被showUser干扰,没提交的时间继承了showUser方法的时间
2. 修饰的方法没有返回值(void) 就在后执行写了@reqmapping的那个方法里面用@ModelAttribute在参数上获取一下先执行方法的返回值
/** * 该方法会先执行 */ @ModelAttribute public void showUser(String uname, Map<String,User> map) throws ParseException { System.out.println("showUser执行了..."); // 通过用户查询数据库拿出一个用户(模拟 这里直接new用户了) User user = new User(); user.setUname(uname); user.setAge(20);//手动改了!!但因为后面只拿表格里的所以并没有影响后面 user.setDate(new Date());//这里继承了这个手动改的因为表格没有提交这个 map.put("abc",user); } /** * ModelAttribute注解 * @return */ @RequestMapping(value="/testModelAttribute") public String testModelAttribute(@ModelAttribute("abc") User user){ System.out.println("testModelAttribute执行了..."); System.out.println(user); return "success"; }
运行结果:
showUser执行了...
testModelAttribute执行了...
User{uname='joker', age=18, date=Thu May 14 14:33:37 CST 2020}
7. SessionAttributes注解
1. 作用:用于多次执行控制器方法间的参数共享(可以用调用servlet原生api得到req,用req.getSession方法获取,但那样耦合性太高)
2. 属性
1). value:指定存入属性的名称
3. 代码如下
这个@SessionAttributes只能作用在类上!!
@SessionAttributes(value={"msg"}) // 把msg=美美存入到session域对中
public class AnnoController {
/** * SessionAttributes的注解 * @return */ @RequestMapping(value="/testSessionAttributes") public String testSessionAttributes(Model model){ System.out.println("testSessionAttributes..."); // 底层会存储到!request域!对象中,域中会显示有这么一个键值对 model.addAttribute("msg","美美"); return "success"; }
success. jsp用EL显示request域
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> <h3>入门成功</h3> <%--加上isELIgnored=false--%> request域对象:${requestScope} </body> </html>
运行结果:点击anno.jsp的超链接后跳到success.jsp
在类上加上注解以后,在success.jsp中加上打印:
<%--加上isELIgnored=false--%> 打印request域对象:${requestScope} 直接打印key为msg所对应的值:${ msg } 用注解把model在req于中添加的键值对存到session域中,然后打印一下session域:${sessionScope}
运行结果:成功把键值对提到了session域里面
session域中的这个数据可以共享了。
获取和删除:
/** * 获取值 * @param modelMap * @return */ @RequestMapping(value="/getSessionAttributes") public String getSessionAttributes(ModelMap modelMap){ System.out.println("getSessionAttributes..."); String msg = (String) modelMap.get("msg"); System.out.println(msg); return "success"; } /** * 清除 * @param status * @return */ @RequestMapping(value="/delSessionAttributes") public String delSessionAttributes(SessionStatus status){ System.out.println("getSessionAttributes..."); status.setComplete(); return "success"; }
anno.jsp里关于session方法是插入超链接跳转到success.jsp
<a href="anno/testSessionAttributes">testSessionAttributes</a> <a href="anno/getSessionAttributes">getSessionAttributes</a> <a href="anno/delSessionAttributes">delSessionAttributes</a>
第一个是上面那个的点击超链接页面,第二个是获取session中的值在控制台输出。第三个是删除值。