SpringMVC(4)
SpringMVC(4)
基础实现
创建新项目
- Group Id为
cn.tedu.spring
, - Artifact Id为
SPRINGMVC-02
, - Packaging为
war
, - 需要实现:访问
http://localhost:8080/SPRINGMVC-02/reg.do
可以打开注册页面,在注册页面中,至少设计用户名、密码、年龄、手机号码、电子邮箱这5个输入框及提交按钮,访问http://localhost:8080/SPRINGMVC-02/login.do
可以打开登录页面,在登录页面中,至少设计用户名、密码这2个输入框及提交按钮,访问http://localhost:8080/SPRINGMVC-02/index.do
可以打开主页,主页显示的内容可以自由定义。 - 提示:同1个控制器类中可以有多个处理请求的方法!
UserController类:
package cn.tedu.spring.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class UserController {@RequestMapping("reg.do")public String showRegister() {System.out.println("showRGISTER.jsp");return "register";}@RequestMapping("login.do")public String showLogin() {System.out.println("showLOGIN.jsp");return "login";}}
MainController类:
package cn.tedu.spring.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class MainController {@RequestMapping("index.do")public String showIndex() {System.out.println("showINDEX.jsp");return "index";}}
register.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Register</title>
</head>
<body><form action="" method="post"><table><tr><td>用户名</td><td><input type="text" name="username"></td></tr><tr><td>密码</td><td><input type="password" name="password"></td></tr><tr><td>年龄</td><td><input type="text" name="age"></td></tr><tr><td>手机号</td><td><input type="text" name="phone"></td></tr><tr><td>电子邮箱</td><td><input type="text" name="email"></td></tr><tr><td><input type="submit" value="注册"></td></tr></table></form>
</body>
</html>
login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body><form action=""><table><tr><td>用户名</td><td><input type="text"></td></tr><tr><td>密码</td><td><input type="password"></td></tr><tr><td><input type="submit"></td></tr></table></form>
</body>
</html>
index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>Index</h1>
</body>
</html>
1、接收客户端提交的请求参数
1.1. 【不推荐】通过HttpServletRequest参数接收请求参数
无法获取HttpServletRequest的request对象,不方便做单元测试
在处理请求的方法中,添加HttpServletRequest
类型的参数,在方法体中,调用参数对象的String getParameter(String name)
方法即可获取请求参数:
@RequestMapping("handle_reg.do")public String handleRegister(HttpServletRequest request) {String username = request.getParameter("username");String password = request.getParameter("password");Integer age = Integer.valueOf(request.getParameter("age"));String phone = request.getParameter("phone");String email = request.getParameter("email");System.out.println("[1]username="+username);System.out.println("[1]password="+password);System.out.println("[1]age="+(age+1));System.out.println("[1]phone="+phone);System.out.println("[1]email="+email);return null;}
这种做法的缺点:
- 使用比较繁琐
- 默认获取的参数值都是 'string’类型,对于其它类型而言,需要自行转换教据类型
- 不易于实现单元测试
1.2. 【推荐】直接将请求参数声明为处理请求的方法的参数
假设客户端提交了名为username
的参数,则在服务器端的控制器的处理请求的方法中,也添加名为username
的参数,即可在方法中获取到请求参数的值,并且,如果希望参数是String
以外的类型,也可以直接声明,例如客户端提交了名为age
的参数,在处理请求的方法中,声明Integer age
即可直接使用:
@RequestMapping("handle_reg.do")public String handleRegister(String username,String password,Integer age,String phone,String email) {System.out.println("[2]username="+username);System.out.println("[2]password="+password);System.out.println("[2]age="+(age+1));System.out.println("[2]phone="+phone);System.out.println("[2]email="+email);return null;}
需要注意的是:使用这种做法时,必须保证客户端提交的参数名,与处理请求的方法中的参数名是一致的!如果不一致,默认情况下,处理请求的方法中的参数值将是null。
这种做法也是缺点的:如果客户端提交的参数的数量非常多,按照这种做法,就需要在处理请求的方法中添加更多的参数,如果处理请求的方法的参数太多,是非常不合适的!
1.3. 【推荐】使用封装了多参数的对象接收请求参数
可以将多个请求参数封装到1个自定义的数据类型中,例如:
package cn.tedu.spring.entity;
public class User {private String username;private String password;private Integer age;private String phone;private String email;}
然后,使用这种类型作为处理请求的方法的参数即可:
@RequestMapping("handle_reg.do")public String handleRegister(User user) {System.out.println("[3]user="+user);return null;}
这种做法也要求名称的统一,即请求参数的名称,与自定义数据类型中的属性名称保持一致。
1.4. 小结
当获取请求参数时,如果参数的数量较少,可以优先选取第2种做法,即直接将请求参数声明为处理请求的方法的参数,如果参数的数量较多,则应该优先选取第3种做法,即使用自定义的数据类型作为处理请求的方法的参数!
在选取这些做法时,还应该评估请求参数是否可能发生变化,特别是数量是否可能发生变化,例如“注册”时,即使只有2个参数,但是,随着业务的更新,可能在后续的功能升级时,会变成4个或更多个参数,则应该使用第3种做法,主要原因是不希望调整控制器的方法!
反之,在例如“登录”功能中,就可以优先使用第2种做法,因为在这个功能中,参数的数量或参数的意义基本上不会发生变化。
并且,以上的第2种做法和第3种做法可以组合使用!例如注册时还需要验证码,则可以使用User
和验证码
作为处理请求的方法的参数!
2、转发与重定向的选取原则
转发与重定向的本质区别在于:在转发过程中,客户端只发出了1次请求,而重定向时,客户端发出了2次请求。在具体的表现中,转发时,客户端浏览器中的地址栏的URL是第1次请求时的URL,重定向时,客户端浏览器的地址栏的URL是第2次请求时的URL。
转发: 当客户端提交请求后,会被服务器端的控制器接收到,并进行处理,处理完成后,应该给予响应,可能需要显示某些数据,但是,控制器是Java类,显示却需要通过HTML及相关技术来完成,Java类是不便于做显示的,所以,就出现了JSP技术,从控制器可以将需要显示的数据转发给JSP,由JSP来完成显示!当然,与Java类的不足非常相似,JSP易于实现显示数据,却不适合完成Java代码的编写!所以,控制器与JSP各有不足,转发就是将这2种技术综合起来互补并解决问题的做法!
附:
JSP就是用来显示数据的,即使JSP中可以使用<% ...%>
标签来编写Java代码,但是,是极不推荐的!而且JSP中显示的数据可能大多来自于控制器的转发,所以,一般也不推荐允许直接访问JSP,而会将JSP放到项目的WEB-INF文件夹中,这样就可以防止客户端直接访问JSP文件!
重定向: 当控制器已经处理完数据,并且,需要用户直接访问下一个界面时,就可以使用重定向的方式进行响应,具体过程是向客户端响应302(大多情况下是302),并给出重定向的目标地址,当客户端接收到302响应码时,就会根据目标地址发出第2次请求。
所以,区分的原则可以是:
- 客户端的浏览器中的URL是否需要发生变化,如果不变,用户刷新是否会是错误的操作;
- 控制器处理完数据后,是否需要显示相关数据。
3、重定向
在控制器中,使用String
作为处理请求的方法的返回值类型,并返回redirect:重定向的目标路径
就可以实现重定向:
@RequestMapping("handle_reg.do")public String handleRegister(User user) {System.out.println("[3]user="+user);//return "redirect:http://localhost:8080/SPRINGMVC-02/login.do";return "redirect:login.do";}
以上重定向的目标路径可以是相对路径,也可以是绝对路径。
4、封装转发的数据
4.1. 【不推荐】使用HttpServletRequest封装转发数据
无法获取HttpServletRequest的request对象,不方便做单元测试
在处理请求的方法的参数列表中,添加HttpServletRequest
类型的参数,当需要转发数据时,调用参数对象的setAttribute(String name,0bject value)
以封装转发数据,最终通过return
语句执行转发即可,无需自行获取转发器:
@RequestMapping("handle_reg.do")public String handleRegister(User user, HttpServletRequest request) {//假设root用户名已经被占用,不允许注册,其它用户名均可成功注册//失败时使用专门的错误页面显示错误信息//成功时,跳转到登录页System.out.println("[3]user="+user);if("root".equals(user.getUsername())) {//封装转发数据String message = "该用户名已被占用!";request.setAttribute("errMsg", message);//执行转发return "error";}else {//注册成功return "redirect:login.do";}//return "redirect:http://localhost:8080/SPRINGMVC-02/login.do";}
4.2. 【不推荐】了解ModelAndView这一数据类型
使用ModelAndView作为处理方法的返回值类型
将处理请求的方法的返回值改成ModelAndView
,当需要转发时,可以使用该类的new ModelAndView(String viewName,Map<String, ?> model)
方式来创建对象,其中String viewName
就是要转发到的视图的名称,Map<String, ?> model
就是用于封装转发数据的对象:
@RequestMapping("handle_reg.do")public ModelAndView handleRegister(User user) {//假设root用户名已经被占用,不允许注册,其它用户名均可成功注册//失败时使用专门的错误页面显示错误信息//成功时,跳转到登录页System.out.println("[3]user="+user);if("root".equals(user.getUsername())) {//注册失败//封装转发数据String message = "[2]该用户名已被占用!";Map<String, Object> model = new HashMap<String, Object>();model.put("errMsg", message);ModelAndView mav = new ModelAndView("error", model);//执行转发return mav;}else {//注册成功return null;}}
4.3. 【推荐】使用ModelMap封装转发的数据
ModelMap是一个类,可以直接new,方便单元测试、
使用ModelMap
封装转发的数据,做法与HttpServletRequest
是相同的:
@RequestMapping("handle_reg.do")public String handleRegister(User user, ModelMap modelMap) {//假设root用户名已经被占用,不允许注册,其它用户名均可成功注册//失败时使用专门的错误页面显示错误信息//成功时,跳转到登录页System.out.println("[3]user="+user);if("root".equals(user.getUsername())) {//注册失败//封装转发数据String message = "[3]该用户名已被占用!";modelMap.addAttribute("errMsg", message);//执行转发return "error";}else {//注册成功return null;}}
4.4. 练习
当用户访问登录页面时(http://localhost:8080/SPRINGMVC-02/login.do
),暂定为admin/1234
是正确的用户名与密码,当用户提交的数据无法登录时,给出对应的错误提示,区分为用户名不存在和密码错误,当用户能够成功登录时,跳转到主页。
@RequestMapping("handle_login.do")public String handleLogin(String username, String password, ModelMap modelMap) {String message;if ("admin".equals(username) && "1234".equals(password)) {// 用户名密码验证成功// 执行重定向return "redirect:index.do";} else if (!"admin".equals(username)) {// 用户名错误message = "用户名不存在!";} else {// 密码错误message = "密码错误!";}// 封装转发数据modelMap.addAttribute("errMsg", message);// 执行转发return "error";}
5、使用Session
5.1. 什么是Session
Http协议是无状态协议,表现为前序请求中产生的数据不会被留下来,后续的请求无法值接使用前序请求中得到的数据!每次客户端与服务器的交互都是请求与响应,然后就结束了!
Session是应用于服务器端较长时间保存数据的技术,它将数据保存在服务器端的内存中,每个浏览器发出请求时,在服务器上对应的Session都是唯一的,由于保存的时间较长所以,可以用于识别用户的身份等。
通常,Session都有15分钟或更长时间的有效期,在此期间内,如果客户端始终与服务器端有交互,则有效期会一直顺延,如果在此期间内没有任何操作,Session会视为超时,即消失,该时间可以由服务器端软件进行设置。
5.2. 何时使用Session
通常,需要使用Session的应用场景有:
- 保存用户的身份的唯一标识,例如用户的id;
- 保存高频率使用的数据,例如用户的用户名、头像等;
- 不便于使用其他技术或解决方案来传输或存储的数据。
5.3. 使用Session
在控制器中,Session的数据类型是HttpSession
,使用方式可以完全参考HttpServletRequest
的使用方式。
@RequestMapping("handle_login.do")public String handleLogin(String username, String password, ModelMap modelMap, HttpSession session) {String message;if ("admin".equals(username) && "1234".equals(password)) {// 用户名密码验证成功// 执行重定向session.setAttribute("username", username);return "redirect:index.do";} else if (!"admin".equals(username)) {// 用户名错误message = "用户名不存在!";} else {// 密码错误message = "密码错误!";}// 封装转发数据modelMap.addAttribute("errMsg", message);// 执行转发return "error";}
index
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h1>欢迎回来!${username }</h1>
</body>
</html>
6、关于@RequestMapping注解
使用@RequestMapping
注解可以配置请求路径与处理请求的方法的映射,即某请求路径将由某方法进行处理。
6.1.
该注解也可以添加在类之前,例如:
@Controller@RequestMapping("user")public class UserController {//......}
一旦在类之前添加了该注解,则该类中配置的所有请求路径的左侧都需要添加user
,即原本http://localhost:8080/项目名/login.do
的路径就会改为http://localhost:8080/项目名/user/login.do
。
推荐为每一个控制器类之前都添加 @RequestMapping
,以统一管理该类中各处理请求的方法映射的路径,并解决多种不同类型的数据处理时,设计请求路径时容易发生同名的问题。
在使用@RequestMapping
配置路径时,不管是添加在类之前的注解,还是添加在方法之前的注解,路径名称的左侧都可以添加/
符号。所以,在类之前的配置和在方法之前的配置可以例如:
/user /login.do
user login.do
/user login.do
user /login.do
以上各种配置都是正确的。在实际使用时推荐使用第1种和第2种。
6.2.
该注解的value
属性的声明是:
@AliasFor("path") //4.2版本以后的Spring,可以使用path替换valueString[] value() default {};
@RequestMapping(value="reg.do")public String showRegister() {System.out.println("showRGISTER.jsp");return "register";}
表示该注解可以配置名为value
的属性,配置时,属性值是String[]
数组类型的,在配置注解时,如果值是某类型的数组,则值可以直接使用该类型的某个对象,或数组类型的对象,例如:
@RequestMapping(value="reg.do")
或@RequestMapping(value={"reg.do", "register.do"})
可以看到,value
属性是用于配置请求路径的,如果配置多个值,则表示无论使用哪个路径,都是对应接下来的这个方法的。
6.3.
在@RequestMapping
注解中,还可以配置method
属性,以限制请求方式,例如:
@RequestMapping(value="handle_reg.do", method=RequestMethod.POST)当注解中有多个属性时,需要写出每个属性的属性名,即:value和method都必须写上。
该注解的method
属性的声明是:
RequestMethod[] method() default {};和上述value属性一样,也可以为method配置多个属性
即表示该请求路径只能接收POST请求,如果一定以GET方式向该路径发出请求,则会出现405错误:
-------------------------------------------------------------------------------
附1. 枚举
假设需要项目中处理用户的性别,并对某个用户的性别进行判断,可以使用String
来描述性别的值,即"男"或"女"。
事实上,并不需要使用String
,而且使用String
也不一定符合当前项目的使用需求,如果当前项目是一个幼儿类的APP,最终在界面上显示的可能是男宝宝
或女宝宝
,不同的APP对于性别的显示文字都是不同的,所以,直接存储男
或女
并没有太多的事实意义,而且字符串的处理相对更加繁琐。
所以,可以使用数值来表示性别,例如约定好使用1表示男性,使用0表示女性,
例如:
int gender = 1;if (gender == 1) {System.out.println("男生");}else {System.out.println("女生");}
如果还是使用String
,则做法就是:
String gender ="男";if ("男".equals(gender)) {System.out.print1n("男生");}else {System.out.println("女生");}
所以,使用数值来表示性别,在处理时比使用String
更加简便。
在使用时,也并不一定是需要用1表示男性,或必须使用0表示女性,只要整个项目都约定相同的规则,值是多少并不重要,例如约定为100表示男性:
int gender = 100;if (gender == 100) {System.out.println("男生");}else {System.out.println("女生");}
如果直接使用数值,并不易于理解代码,更加推荐使用某个量来表示:
int gender_male = 100;
并在使用时:
int gender = gender_male;if (gender == gender_male) {System.out.println("男生");}else {System.out.println("女生");}
在这个做法中,更关注的就不再是100这个数字,而是 gender_male
这个名称对应的意义。
这个量很可能需要多处使用,为了便于统一使用、一次创建反复使用、常驻内存随时使用,可以:
public static int gender_male = 100;
由于多处都可以使用这个量,万一某个位置对该量的值进行修改,就会导致程序错误!所以:
public static final int GENDER_MALE = 100;
这种量可能存在于某个类中,而项目中如果有多个类似用途的量,反复这样声明,语法表现得非常繁琐,为了提高编码效率,可以使用接口,就可以省去声明语句中的public static final
部分:
public interface Gender{int GENDER_MALE = 100;int GENDER_FEMALE = 200;}
同时,由于并不关心其数据类型,也不关心具体的值是多少,所以,就出现了枚举类型:
public enum Gender{GENDER_MALE,GENDER_FEMALE;}
枚举类型可以保证其中每个的值都是不冲突,即以上代码中的GENDER_MALE
和GENDER_FEMALE
的值一定不同,至于具体是多少,可以不必关心,这些类的类型都是枚举的Gender
类型。
RequestMethod就是枚举类型。
public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE}
SpringMVC(4)相关推荐
- java元婴期(30)----java进阶(springmvc(4)---参数绑定(下)springmvc校验异常处理)
包装类型pojo参数绑定 需求 商品查询controller方法中实现商品查询条件传入. 实现方法 第一种方法:在形参中 添加HttpServletRequest request参数,通过reques ...
- java元婴期(29)----java进阶(springmvc(3)---springmvc和mybatis整合参数绑定(上))
springmvc和mybatis整合 需求 使用springmvc和mybatis完成商品列表查询. 整合思路 springmvc+mybaits的系统架构: 第一步:整合dao层 mybatis和 ...
- java元婴期(28)----java进阶(springmvc(2)---入门程序(下)基于注解开发(重点掌握))
入门程序 非注解的处理器映射器和适配器 1.非注解的处理器映射器 处理器映射器: org.springframework.web.servlet.handler.BeanNameUrlHandlerM ...
- java元婴期(27)----java进阶(springmvc(1)---springmvc框架入门程序(上)(不基于注解开发))
springmvc框架 什么是springmvc springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合.(struts2与Spring整合的时候需 ...
- spring-mvc(基础)
一.MVC框架的概述 1.作用 ①支持直接一个方法对一请求 ② 支持数据的自动封装 ③ 自动支持上传组件 ④ 自动支持JSON的转成 2.配置流程图 3.基于xml的配 ...
- SpringMVC(笔记)
MVC简介 普通的web项目每次都要进行手动的把jar包导进去,否则会报500,class not found [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VstjH ...
- SpringMVC(一)视图解析器
springMVC是一个基于spring的一个框架,实际上 就是spring的一个模块,专门做web开发. 是servlet的一个升级. web开发的底层是servlet,框架是再servlet基础上 ...
- SpringMVC(三)-- springmvc的系统学习之数据的处理,乱码及restful
资源:尚学堂 邹波 springmvc框架视频 一.提交数据的处理 1.提交的域名称和处理方法的参数一致 (1)提交的数据:http://localhost:8080/data/hello.do?na ...
- SpringMVC(一·)
SpringMVC入门 一 .MVC模式与Spring MVC工作原理 1.1 MVC模式 1.1.1 MVC的概念 1.1.2 基于Servlet的MVC模式 1.2 Spring MVC工作原理 ...
最新文章
- Flutter-现有iOS工程引入Flutter
- 若微型计算机在工作时突然断电,16秋《计算机基础》作业1
- Windows下RabbitMQ安装及入门
- phpMyAdmin出现错误 Access denied for user 'root'@'localhost' (using password: NO)
- 第四部分 在configure.in中使用宏来检测
- 40个全球免费开放的电子图书馆
- 如何读懂3GPP协议
- 预测未来的神技---马尔科夫模型
- 批量删除文件名前的数字编号
- 抗光幕布哪个牌子好?
- MacOS 校验iso sha256值、md5值,linux
- java 获取某一天的起始时间
- google浏览器(chrome)登录、同步
- Deep Reinforcement Learning for Sepsis Treatment文献阅读记录
- 计算机网络第一章考研题
- 《弃子长安》第八章 昨日黄花
- 高德地图开发-常用api踩坑使用
- 2022年中式烹调师(初级)模拟试题及中式烹调师(初级)模拟考试
- Flashnbsp;AS3nbsp;学习7nbsp;-nbsp;计时器
- CleanMyMac4.12最新Mac电脑系统垃圾清理神器
热门文章
- JAVA 150道笔试题知识点整理
- 不卸载原有mysql直接安装mysql8.0
- 重装系统后鼠标一直转圈的问题
- 啦啦餐饮外卖系统V42.2.0独立版全插件开源去后门源码同城APP小程序 完美经营-有演示
- 用c#算成绩的总和_c#编写一个学生成绩计算程序,统计出一个班学生的某门课程各分数段的人数(分数段:90分以上,80-90,70-80,...
- linux平台xpt2046驱动,XPT2046触摸屏实验过程详解与STM32代码解析
- ICRA 2022 优秀论文
- 三星液晶拼接屏厂家有哪些 液晶拼接屏特点介绍
- 《啤酒与饮料》python
- 万字好文,电商秒杀系统架构分析与实战!