Spring MVC 开发(二)

1. 关于@RequestParam注解

1.1. 基础使用

使用@RequestParam注解,可以解决提交的请求参数与处理请求的方法参数名称不一致的问题,例如:

@RequestMapping("/handle_login.do")
public String handleLogin(
        @RequestParam("uname") String username,
        String password) {
    System.out.println("username=" + username);
    System.out.println("password=" + password);
    return null;
}

使用@RequestParam注解后,默认情况下,对应的请求参数是必须的,如果提交的请求不包含这项参数,则会提示:

HTTP Status 400 - Required String parameter 'uname' is not present

1.2. 注解的配置

使用@RequestParam注解请求参数名称时的完整语法是:

@RequestParam(value="uname")

@RequestParam注解中,还有另一个属性required,取值为boolean类型,例如:

@RequestParam(value="uname", required=false)

可以发现,使用@RequestParam时,其required属性的默认值是true

除此以外,该注解还有一个String类型的属性defaultValue

@RequestParam(value="uname", required=false, defaultValue="hello")

这项defaultValue表示的是默认值,即没有提交这项请求参数时,将按照默认值来处理,如果提交了这项请求参数,则这项配置没有意义。

从4.2版本后,该注解还可以使用name属性,意义与value属性相同。

/**
 * The name of the request parameter to bind to.
 * @since 4.2
 */
@AliasFor("value")
String name() default "";

2. 转发数据

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

当需要转发数据时,可以在处理请求的方法中添加HttpServletRequest对象作为参数,然后调用该参数对象的setAttribute(String, Object)方法封装即可:

@RequestMapping("/handle_reg.do")
public String handleReg(User user, 
        HttpServletRequest request) {
    System.out.println(user);
    
    // 暂视为所有用户名注册时都是失败的,原因:用户名已经被占用
    // 封装错误信息,以准备转发
    String message = "您输入的用户名(" + user.getUsername() 
            + ")已经被占用!";
    request.setAttribute("message", message);
    
    // 执行转发
    return "error";
}

2.2. 【不推荐】使用ModelAndView

在处理请求时,使用ModelAndView作为方法的返回值。

ModelAndView中,Model表示需要转发的数据,其类型是Map<String, ?>类型,View表示负责响应的视图组件,可以使用String viewName表示。

@RequestMapping("/handle_reg.do")
public ModelAndView handleReg(String username) {
    // 暂视为所有用户名注册时都是失败的,原因:用户名已经被占用
    String message = "MODEL:您输入的用户名(" 
            + username + ")已经被占用!";
    
    // 封装转发的数据
    Map<String, Object> model 
        = new HashMap<String, Object>();
    model.put("message", message);
    
    // 准备返回值
    ModelAndView mav
        = new ModelAndView("error", model);
            
    // 执行转发
    return mav;
}

2.3. 【推荐】使用ModelMap

ModelMap是SpringMVC中提供的用于封装转发数据的类型,其本质就是一个Map,你可以像使用一般的Map类似的方式去使用它,同时,当你需要封装转发数据时,使用与HttpServletRequest相同的方式去使用即可!

@RequestMapping("/handle_reg.do")
public String handleReg(String username,
        ModelMap modelMap) {
    // 暂视为所有用户名注册时都是失败的,原因:用户名已经被占用
    String message = "MODELMAP:您输入的用户名(" 
            + username + ")已经被占用!";
    
    // 封装需要转发的数据
    modelMap.addAttribute("message", message);
    
    // 执行转发
    return "error";
}

3 重定向

在处理请求的方法中,返回值类型依然使用String,并且,返回的字符串使用redirect:作为前缀,然后写出目标位置的相对路径或绝对路径。

// 重定向
@RequestMapping("/handle_reg.do")
public String handleReg() {
    // 假设注册一定成功,并到登录页
    // 当前位置:        /user/handle_reg.do
    // 重定向到登录,即:/user/login.do
    return "redirect:login.do";
}

4. 处理Session

ModelMap的使用方式是一样的!即:把HttpSession作为参数添加到处理请求的方法中,然后,这整个方法中就可以使用Session。

5. 关于@RequestMapping

使用@RequestMapping主要用于配置所处理的请求的路径,完整配置应该是:

@RequestMapping(value="/handle_reg.do")

除此以外,还可以添加配置method属性,以限制请求的类型,例如:

@RequestMapping(value="/handle_reg.do", method=RequestMethod.POST)

如果以上路径配置了限制为POST请求,然后,实际发出的是GET请求,则会提示405错误:

HTTP Status 405 - Request method 'GET' not supported

通常,对于GET类型的请求并不配置method,而POST类型的请求应该配置method。但是,出于规范的考虑,无论什么请求,都应该显式的限制请求类型,除非你确定这些请求类型都是允许的。

6. 阶段小结

SpringMVC主要解决了如何接收请求,并给予的响应的问题。

在处理请求时,请求的参数(含多个请求参数构成的对象类型)、HttpServletRequestHttpServletResponseModelMapHttpSession都可以根据需要,自行添加为处理请求的方法的参数,然后,在方法内部直接使用即可!

处理请求的方法返回值可以是String,默认的响应方式是转发,如果需要重定向,则返回的字符串应该是redirect:相对路径或绝对路径

使用@RequestMapping注解可以配置请求路径,甚至限制请求类型。

使用@RequestParam注解可以确定请求参数的名称、是否必须、默认值。

7. 阶段案例

7.1. 案例目标

用户可以在注册页面中填写:用户名、密码、年龄,提交后,暂且将admin用户名视为已注册,即当用户提交的用户名是admin时,提示错误,否则,视为注册成功!

如果注册成功,则跳转到登录页,在处理登录时,如果用户名是root且密码是1234,视为登录成功,否则,视为登录失败!

如果登录成功,将用户名存储在Session中,并跳转到主页,要求在主页中显示当前登录的用户名。

以上请求的路径分别是:

  • 显示注册页面:/user/reg.do
  • 显示登录页面:/user/login.do
  • 处理注册请求:/user/handle_reg.do
  • 处理登录请求:/user/handle_login.do
  • 显示主页:/main/index.do

7.2. 开发步骤

7.2.1. 创建项目

创建Maven Project,Group Id为cn.tedu.spring,Artifact Id为SPRINGMVC-03-SAMPLE,Packaging为war,然后,执行固定的5项任务:生成web.xml,复制此前项目中pom.xml中依赖,添加Tomcat Runtime,复制springmvc.xml,复制此前项目中web.xml中关于DispatcherServlet的配置。

7.2.2. 分析案例

一次只解决一个问题。

先下手为强。

大致的开发步骤应该分为:

  • 显示注册页面

  • 处理注册数据

  • 显示登录页面

  • 处理登录数据

  • 显示主页

7.2.3. 显示注册页面

设计请求:

请求路径:/user/reg.do
请求方式:GET
请求参数:无
响应方式:转发:reg.jsp

创建cn.tedu.spring.controller.UserController类,使用@Controller@RequestMapping("/user")注解。

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

@RequestMapping("/reg.do")
public String showReg() {
    return "reg";
}

检查springmvc.xml的配置是否符合当前项目,例如组件扫描的包,视图解析器的前缀与后缀的配置。

然后,在webapp/WEB-INF下创建reg.jsp页面,在页面中添加用户名、密码、年龄的输入框和提交按钮,且表单以POST方式提交到handle_reg.do

7.2.4. 处理注册数据

设计请求:

请求路径:/user/handle_reg.do
请求方式:POST
请求参数:User(username, password, age),ModelMap
响应方式:成功时重定向到/user/login.do,失败时转发到error.jsp

先创建cn.tedu.spring.entity.User类,并声明以上3个属性,参考Java Bean设计规范。

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

@RequestMapping("/handle_reg.do")
public String handleReg(User user, ModelMap modelMap) {
    // 判断用户名是否是"admin"
    // -- 是:视为失败,用户名被占用
    // -- -- 向ModelMap对象中封装需要转发的数据:错误信息
    // -- -- 执行转发
    // -- 否:视为成功
    // -- -- 重定向到/user/login.do
}

最后,创建error.jsp,并在页面中通过EL表达式显示错误信息。

练习

SPRINGMVC-03-SAMPLE案例中继续完成:

显示登录页面

分析请求:

请求路径:/user/login.do
请求类型:GET
请求参数:无
响应方式:转发

所以,在UserController中添加处理请求的方法:

@RequestMapping("/login.do")
public String showLogin() {
    return "login"; // /WEB-INF/login.jsp
}

复制并调整现有的reg.jsp,得到login.jsp

处理登录数据

分析请求:

请求路径:/user/handle_login.do
请求类型:POST
请求参数:username, password, ModelMap, HttpSession
响应方式:成功时重定向到/main/index.do,失败时转发到error

所以,在UserController中添加处理请求的方法:

@RequestMapping(value="/handle_login.do", 
    method=RequestMethod.POST)
public String handleLogin(
    @RequestParam("username") String username,
    @RequestParam("password") String password,
    ModelMap modelMap, HttpSession session) {
    // 如果用户名是`root`且密码是`1234`,视为登录成功,否则,视为登录失败!
    // 判断用户名是否为root
    //      用户名正确 > 判断密码是否为1234
    //          密码正确 > 登录成功 > 记Session
    //              重定向到/main/index.do
    //          密码错误    > 封装错误信息
    //              转发到error
    //      用户名错误 > 封装错误信息:用户名或密码错误
    //          转发到error
}

显示主页

分析请求:

请求路径:/main/index.do
请求类型:GET
请求参数:无
响应方式:转发

由于此次的路径是/main而不是之前的/user,所以,必须新建另一个控制器类来完成,则创建cn.tedu.spring.controller.MainController,和之前的控制器类一样,添加2项注解。

然后,在这个新创建的控制器类中添加处理请求的方法:

@RequestMapping("/index.do")
public String showIndex() {
    return "index"; // /WEB-INF/index.jsp
}

然后,复制error.jsp得到login.jsp

其它

1. 关于构造方法

每个类都有构造方法,用于确定对象的创建过程,当需要创建对象时,使用例如new Object();这样的语法,就是在调用构造方法。

在编写类的时候,可以不需要显式的编写构造方法,当没有显式的编写时,编译器将自动添加公有的、无参数的构造方法!如果已经显式的编写了任何构造方法,编译器将不会自动添加构造方法!

构造方法也是方法,可以重载。

每次创建对象时,都会默认先调用其父类的构造方法!即:

public class User {
    public User() {
        super(); // 调用其父类的构造方法
    }
}

且:使用super关键字调用父类的构造方法的语句,必须编写在子类的构造方法中,必须是子类构造方法中的第1条有效代码!

抽象类的构造方法不允许直接调用,即不允许使用new语法调用抽象类的构造方法来直接创建抽象类的对象!

通常,会在以下情景中自定义构造方法:

  1. 更便捷的创建对象,会自定义若干个带参数的构造方法,使得创建对象时就可以直接确定某些属性的值;

  2. 需要确定创建对象时,就执行的任务,或确定某些属性的值;

  3. 需要限制创建对象,可能将构造方法的访问权限设置得更加严格!

由于使用的系统不同,可能某些系统上快捷键不同,或会发生冲突,如果无法调整,则应该使用Source菜单中对应的功能。

2. 转发与重定向

转发的本质是客户端只发出了1次请求,而重定向的话,客户端发出了2次请求。

转发是发生在服务端内部的,对于客户端而言,并不知道服务端内部有转发的过程,即使是控制器(无论是SpringMVC中的Controller还是传统的Servlet)转发到了JSP,对于客户端而言,也并不知晓。

在执行转发时,URL是不会发生变化的,而重定向会发生变化!

如果需要将较多的数据进行传递,可以使用转发!而重定向则不适合大量数据的传递,因为重定向对应的是2次请求,而2次请求之间数据并不共享!

如果需要地址栏发生变化,与当前页面显示的内容匹配,则必须使用重定向!

3. 关于响应码

服务端对客户端进行响应时,除了有响应的正文以外,还会有响应代码。常见的响应码:

  • 2xx:正确响应,例如:200、206

  • 3xx:重定向,例如:301、302

  • 4xx:请求错误,例如:400、404、405、406

  • 5xx:服务器内部错误,例如:500

4. 枚举类型

使用enum关键字可以声明枚举类型,例如:

public enum RequestMethod {

    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE

}

定义枚举的前提是:可以穷举所有可能的值,每个值都不相同,并不关心值本身而只关心它表达的意义。

猜你喜欢

转载自www.cnblogs.com/wood-life/p/10289306.html