Spring MVC day02

mac2024-02-19  31

2. 使用SpringMVC框架开发WEB项目

2.5. 显示页面

在SpringMVC中,当控制器接收到请求后,可以通过JSP页面向客户端呈现数据,或者使用其它的页面技术,例如Thymeleaf等。

如果需要使用Thymeleaf来呈现页面与数据,则需要在项目中添加Thymeleaf依赖,与Thymeleaf整合Spring的依赖:

<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>3.0.11.RELEASE</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>3.0.11.RELEASE</version> </dependency>

此前在控制器中返回String类型的数据,其值就是ModelAndView中的View,即返回的字符串表示视图名称,则需要通过ViewResolver得到视图组件,在使用Thymeleaf时,需要使用的ViewResolver是ThymeleafViewResolver:

<!-- 配置模版解析器 --> <!-- 1. ClassLoaderTemplateResolver,文件需要放在resources下 --> <!-- 2. ServletContextTemplateResolver,文件需要放在webapp下 --> <bean id="templateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver"> <property name="prefix" value="/templates/" /> <property name="suffix" value=".html" /> <property name="characterEncoding" value="utf-8" /> <property name="templateMode" value="HTML" /> <property name="cacheable" value="false" /> </bean> <!-- 配置模版引擎 --> <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver" /> </bean> <!-- 配置视图解析器 --> <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine" /> <property name="characterEncoding" value="utf-8" /> </bean>

最后,在src/main/resources/下创建templates文件夹,并在文件夹下创建hello.html文件,并将控制器中处理请求的方法的返回值改为"hello"即可:

@RequestMapping("hello.do") public String showHello() { System.out.println("UserController.showHello()"); return "hello"; }

3. 创建新的案例

3.1. 案例目标

在浏览器中,输入http://localhost:8080/SpringMVC02/reg.do,在页面中将显示用户注册页面,在页面中,至少包含用户名、密码、年龄、手机号码、电子邮箱这5个输入框,和1个提交按钮。

3.2. 创建项目

创建Maven Project,创建时勾选Create a simple project,Group Id输入cn.tedu.spring,Artifact Id输入SpringMVC02,Packaging选择war。

当项目创建完成后,需要:

生成web.xml文件;

添加Tomcat运行环境;

从前序项目的pom.xml中复制依赖的代码到当前项目中;

将前序项目中的spring.xml复制到当前项目中;

将前序项目中的web.xml中关于DispatcherServlet的配置复制到当前项目中;

检查web.xml中关于DispatcherSerlvet配置中加载的Spring配置文件的名称是否正确。

3.3. 通过控制器接收并处理请求

创建cn.tedu.spring包(请检查spring.xml中配置的组件扫描是否与之一致),并在该包之下创建UserController,在类的声明之前添加@Controller注解:

package cn.tedu.spring; import org.springframework.stereotype.Controller; @Controller public class UserController { }

然后,在类中添加处理请求的方法:

@RequestMapping("reg.do") public String showReg() { // /templates/reg.html return "user/reg"; // 返回值可以理解为即将要创建的html文件的名称 }

3.4. 显示页面

先检查spring.xml是否存在关于视图解析器的配置,如果没有,从前序项目中复制过来!

检查关于视图解析器中的配置,如果使用的模版解析器是ClassLoaderTemplateResolver,则需要将HTML文件创建到src/main/resource下,如果使用的是ServletContextTemplateResolver,则需要将HTML文件创建到webapp下!

再检查模版解析器中配置的前缀,以决定是否需要创建文件夹!

然后,在指定的文件夹中创建HTML页面。

4. 接收客户端提交的请求参数

4.1. 【不推荐】通过HttpServletRequest接收请求参数

可以在处理请求的方法的参数列表中添加HttpServletRequest类型的参数,在处理过程中,调用该参数对象的getParameter()方法即可获取客户端(例如网页)中提交的请求参数:

@RequestMapping("handle_reg.do") public String handleReg(HttpServletRequest request) { System.out.println("UserController.handleReg()"); String username = request.getParameter("username"); String password = request.getParameter("password"); String age = request.getParameter("age"); String phone = request.getParameter("phone"); String email = request.getParameter("email"); System.out.println("username=" + username); System.out.println("password=" + password); System.out.println("age=" + age); System.out.println("phone=" + phone); System.out.println("email=" + email); return null; }

一般,并不推荐使用这种方式接收请求参数!主要原因有:

获取参数的过程比较麻烦;

如果需要的参数不是String类型,则需要自行转换数据类型;

不便于执行单元测试。

4.2. 【推荐】直接将请求参数声明为处理请求的方法的参数

可以将请求参数声明为处理请求的方法的参数,使用时,可以直接将参数的类型声明为所期望的类型,例如希望age是数值型的,就可以直接声明为Integer或int类型:

@RequestMapping("handle_reg.do") public String handleReg(String username, String password, Integer age, String phone, String email) { System.out.println("UserController.handleReg()"); System.out.println("username=" + username); System.out.println("password=" + password); System.out.println("age=" + (age + 1)); System.out.println("phone=" + phone); System.out.println("email=" + email); return null; }

使用这种做法时,需要保证请求参数的名称,与处理请求的方法中的参数名称是一致的!如果不一致,则处理请求的方法的参数值是null。

这种做法简单,直接,便于执行单元测试,但是,不适用于请求参数的数量较多的应用场景!

4.3. 【推荐】使用封装的类型作用请求参数

当请求参数的数量较多时,可以先创建User类,在类中声明所有需要接收的请求参数:

public class User { private String username; private String password; private Integer age; private String phone; private String email; }

注意:以上这种类,必须存在无参数的构造方法,并且,相关属性必须有正确的SET方法!

然后,将User作为处理请求的方法的参数即可:

@RequestMapping("handle_reg.do") public String handleReg(User user) { System.out.println("UserController.handleReg()"); System.out.println(user); System.out.println(user.getUsername()); System.out.println(user.getPassword()); System.out.println(user.getAge()); System.out.println(user.getPhone()); System.out.println(user.getEmail()); return null; }

这种做法也是SpringMVC推荐的做法!

4.4. 小结

以上3种获取请求参数的做法中,首先,始终不使用第1种做法!

当请求参数的数量较少,并且相对固定时,优先使用第2种(逐一声明所有参数)做法,否则,请求参数数量较多,或参数可能调整时,优先使用第3种(封装所有请求参数)做法!

并且,以上第2种做法和第3种做法可以同时使用!

5. 数据转发

5.1. 【不推荐】通过HttpServletRequest转发数据

在处理请求的方法的参数列表中添加HttpServletRequest参数,然后,在处理过程中,将需要转发的数据封装在HttpServletRequest对象中即可,例如:

String errorMessage = "登录失败!密码错误!"; request.setAttribute("msg", errorMessage);

完整代码示例:

@RequestMapping("handle_login.do") public String handleLogin( HttpServletRequest request, String username, String password) { System.out.println("UserController.handleLogin()"); System.out.println("username=" + username); System.out.println("password=" + password); // 假设root/1234是正确的用户名和密码 // 先判断用户名是否正确 if ("root".equals(username)) { // 用户名正确,判断密码 if ("1234".equals(password)) { // 密码也正确,则登录成功 } else { // 密码错误 String errorMessage = "登录失败!密码错误!"; request.setAttribute("msg", errorMessage); return "error"; } } else { // 用户名错误 String errorMessage = "登录失败!用户名错误!"; request.setAttribute("msg", errorMessage); return "error"; } return null; }

后续,在HTML模版页面中,可以通过Thymeleaf表达式显示这些数据,例如:

<h3 th:text="${msg}"></h3>

如果处理请求的方法中有多个参数,在设计参数时,各参数并不区分先后顺序!

使用HttpServletRequest依然存在不便于执行单元测试的问题!

5.2. 【推荐】通过ModelMap转发数据

关于ModelMap的使用方式,与HttpServletRequest基本一致!

代码示例:

@RequestMapping("handle_login.do") public String handleLogin( ModelMap modelMap, String username, String password) { System.out.println("UserController.handleLogin()"); System.out.println("username=" + username); System.out.println("password=" + password); // 假设root/1234是正确的用户名和密码 // 先判断用户名是否正确 if ("root".equals(username)) { // 用户名正确,判断密码 if ("1234".equals(password)) { // 密码也正确,则登录成功 } else { // 密码错误 String errorMessage = "登录失败!密码错误!"; modelMap.addAttribute("msg", errorMessage); return "error"; } } else { // 用户名错误 String errorMessage = "登录失败!用户名错误!"; modelMap.addAttribute("msg", errorMessage); return "error"; } return null; }

使用ModelMap时,相比HttpServletRequest,更加易于执行单元测试,并且,ModelMap的对象更加轻量级。

5.2. 【不推荐】使用ModelAndView作为处理请求的方法的返回值

将方法的返回值类型声明为ModelAndView,创建ModelAndView对象时,调用其ModelAndView(String viewName, Map<String, ?> model)构造方法,就可以快速的设置返回的视图名称(viewName)和数据(model)。

@RequestMapping("handle_login.do") public ModelAndView handleLogin( String username, String password) { System.out.println("UserController.handleLogin()"); System.out.println("username=" + username); System.out.println("password=" + password); ModelAndView mav; // 假设root/1234是正确的用户名和密码 // 先判断用户名是否正确 if ("root".equals(username)) { // 用户名正确,判断密码 if ("1234".equals(password)) { // 密码也正确,则登录成功 } else { // 密码错误 String errorMessage = "登录失败!密码错误!"; Map<String, Object> model = new HashMap<String, Object>(); model.put("msg", errorMessage); mav = new ModelAndView("error", model); return mav; } } else { // 用户名错误 String errorMessage = "登录失败!用户名错误!"; Map<String, Object> model = new HashMap<String, Object>(); model.put("msg", errorMessage); mav = new ModelAndView("error", model); return mav; } return null; }

-------------------------

附1:关于No Mapping Found错误的解决方案

该错误是在控制台提示的错误:

No mapping found for HTTP request with URI [/SpringMVC01/hello.do] in DispatcherServlet with name 'SpringMVC'

同时,在浏览器中,会显示404错误。

出现这种错误的原因可能有:

在Spring的配置文件中没有配置组件扫描;

控制器类没有放在组件扫描的包或其子包中;

控制器类没有添加@Controller注解,或者,添加了其它例如Component注解;

在控制器类中,处理请求的方法没有添加@RequestMapping注解;

在浏览器中输入的请求路径与控制器中配置的路径不一致。

附2:关于GET请求与POST请求

附3:封装

最新回复(0)