Spring MVC学习总结(二):基于注解的控制器+Controller接收请求参数的常见方式+重定向与转发区别+应用@Autowired和@Service依赖注入+@ModelAttribute

基于注解的控制器类

在(一)中,创建第一个应用中,Contoller中使用的是传统的控制器风格,传统的控制器只能编写一个处理方法,

而且需要在springmvc-servlet.xml部署映射,

如果有多个相关的处理方法就需要写多个控制类,部署多次映射,所以,spring mvc 引入了基于注解的控制类,其优点在于:

1、在基于注解的控制器类中,可以有多个处理方法,多个请求,这就可以使相关的处理方法可以写在一个类中,从而减少了控制器类的数量。

2、在基于注解的控制器类中,无需再在配置文件中部署映射,仅需使用RequestMapping 和Controller注释即可。

 

下面我们将第一个项目中控制器类修改为基于注解的控制器类,我们需要修该以下几个地方:

将两个控制器类修改为一个控制器类:LoginController.java和RegisterController.java合并为IndexController.java:

package controller1;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller//这个注解需写在类名上头,表示该类是控制器类
public class IndexController {
@RequestMapping(value="login")//这个注释有两种类型的写法,下面将介绍
public String login() {
	return "login";//login代表逻辑视图名称
}
@RequestMapping(value="register")
public String register() {
	return "register";
}
}

Springmvc 使用扫描机制扫描所有基于注解的控制器类,使用

<context:component-scan base-package="基于注解的控制器类所在的包"/>

在springmvc-servlet.xml配置文件中注册控制器类所在的包:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-4.3.xsd">
          <!-- 使用扫描机制,扫描控制器类,控制器类都在controller1包及包下 -->
         <context:component-scan base-package="controller1"/>
          <!-- LoginController控制器类,映射到”/login“ -->
<!--           <bean name="/login" class="controller.LoginController"/>   -->
          
           <!-- RegisterController控制器类,映射到”/register“ -->
<!--           <bean name="/register" class="controller.RegisterController"/> -->
          
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                id="internalResourceViewResolver">
           <!-- 前缀    --> 
           <property name="prefix" value="/WEB-INF/jsp/"/>
          <!--  后缀 -->
           <property name="suffix" value=".jsp"/> 
                
           </bean>  
           
          </beans>

其中RequestMapping可分为方法级别注释和类级别注释,上面属于方法级别注释,下面将介绍类级别注释

若将请求页面地址修改为如图:

将控制器类修改为类名上上一个RequestMapping,方法名上在写一个RequestMapping,这种方法适用于当请求名特别长的时候,但前缀相同的情况,类似如图Controller类修改为:

package controller1;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping(value="/login")
public String login() {
	return "login";//login代表逻辑视图名称
}
@RequestMapping(value="/register")
public String register() {
	return "register";
}
}

控制器类接受请求参数的常见方式:

1、使用实体bean来接受请求参数:

如下代码所示:

package controller1;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import domain.User;

@Controller

public class IndexController {
@RequestMapping(value="login")
public String login() {
	return "login";//login代表逻辑视图名称
}
@RequestMapping(value="register")
//
public String register(User user) {
        System.out.println("username:"+user.getUsername());
	if("hxz".equals(user.getUsername())&&"123".equals(user.getPassword())) {
		return "login";
	}else {
		
		return "register";
	}
	
}
}

创建实体bean:

package domain;

public class User {
 private String username;
 private String password;
public String getUsername() {
	return username;
}
public void setUsername(String username) {
	this.username = username;
}
public String getPassword() {
	return password;
}
public void setPassword(String password) {
	this.password = password;
}
 
}

修改register.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>注册</title>
</head>
<body>
<form action="register" method="post" >
用户名:<input type="text" name="username" size=6>
密码:<input type="password" name="password" size=6>
确认密码:<input type="password" size=6>
<input type="submit" value="注册">
</form>
</body>
</html>

修改以后可以成功跳转,控制台打印如下:

为什么会出现刚开始会null?

因为我在第一次发请求时:

请求的时register,

此处提交请求时还没有输入内容,所以当然是null啦,

在后面的注册页面发的请求仍然是register,

此处提交请求时已输入用户名和密码,所以会输出。

2、通过形参接受请求参数:

public String register(String username,String password) {
	System.out.println("username:"+username);
	if("hxz".equals(username)&&"123".equals(password)) {
		return "login";
	}else {
		
		return "register";
	}
	

3,通过@PathVariable接收URL中的请求参数:

	@RequestMapping(value="/two/{uname}/{upass}", method=RequestMethod.GET)
	public String register(@PathVariable String uname,@PathVariable String upass, Model model) {
		if("zhangsan".equals(uname) 
				&& "123456".equals(upass))
			return "login";//注册成功,跳转到login.jsp
		else{
			//在register.jsp页面上可以使用EL表达式取出model的uname值
			model.addAttribute("uname", uname);
			return "register";//返回register.jsp
		}
	}

4、通过HttpServletRequest接收请求参数:

@RequestMapping("/register")
public String register(HttpServletRequest request, Model model) {
	String uname = request.getParameter("username");
	String upass = request.getParameter("password");
	if("zhangsan".equals(uname) 
			&& "123456".equals(upass))
		return "login";//注册成功,跳转到login.jsp
	else{
		//在register.jsp页面上可以使用EL表达式取出model的uname值
		model.addAttribute("uname", uname);
		return "register";//返回register.jsp
	}
}

5、通过@RequestParam接收请求参数

	/**
	 * 通过@RequestParam接收请求参数
	 */
	public String register(@RequestParam String uname, @RequestParam String upass, Model model) {
		if("aa".equals(uname) 
				&& "123".equals(upass))
			return "login";//注册成功,跳转到login.jsp
		else{
			//在register.jsp页面上可以使用EL表达式取出model的uname值
			model.addAttribute("uname", uname);
			return "register";//返回register.jsp
		}
	}
}

由于前面提到过,两次请求处理方法都是register,但上面这个处理方法写出来以后,要求带有参数才能用这个处理方法,所以需要为第一次请求再重写一个 处理方法,否则会404.

	@RequestMapping("/register")
	public String register(){
		return "register";
	}

6、通过@ModelAttribute接收请求参数

通过@ModelAttribute注解在处理方法上时,可以将多个请求参数封装在一个实体对象中,简化数据绑定流程,自动暴露为模型数据,于视图页面展示时使用

	@RequestMapping("/register1")
	public String register(@ModelAttribute("user") UserForm user) {
		if("zhangsan".equals(user.getUname()) 
				&& "123456".equals(user.getUpass()))
			return "login";//注册成功,跳转到login.jsp
		else{
			//使用了@ModelAttribute("user")和使用了model.addAttribute功能相同
			//model.addAttribute("uname", user.getUname());
			return "register";//返回register.jsp
		}
	}

重定向与转发:

区别:

  1. 重定向是将用户当前请求重定向到另一个请求或视图,其中request储存的信息全部失效,并进入到一个心得request作用域,而转发是将用户当前请求转发到另一个请求或视图,request作用域不会失效。
  2. 重定向是客户端行为,客户发送请求,服务器发回302状态码响应,并将新的location发送给客户端,浏览器发现是302,便对新的location发送请求;而转发是服务器行为,在同一个web容器内实现,所以只能转发到同一容器下的url。
  3. 重定向,地址栏会发生变化;转发地址栏不会发生变化。
  4. 转发相当于一次请求,而重定向相当于两次请求。

 在spring MVC 框架中 return语句中默认是转发请求

以下代码展示了这两种区别:

public class IndexController {
	@RequestMapping("/login")
	public String login() {
		/*不管重定向或转发,都需要符合视图解析器的配置,如果直接跳转到一个不需要dispatcher servlet的资源,
		 * 需要使用mvc:resources配置,
		如:<mvc:resources location="/html/" mapping="/html/**"></mvc:resources> )
		return "forward:/html/my.html";*/
		//转发到一个请求方法(同一个控制器类里,可省略/index/)
		//return "forward:/index/isLogin";
		return "login";
	}
	@RequestMapping("/isLogin")
	public String isLogin() {
		//重定向到一个请求方法
		return "redirect:/index/isRegister";
	}
	@RequestMapping("/isRegister")
	public String isRegister() {
		//转发到一个视图,jsp页面
		return "register";// 默认是转发打开*.jsp
	}
	@RequestMapping("/register")
	public String register() {
		return "register";
	}
}

转发地址栏: 

 重定向地址栏:

应用@Autowired和@Service进行依赖注入

依赖注入又称为控制反转,框架自动对要使用的bean对象进行实例化,并不需要你手动实现,控制权由程序员交给了容器。

在上面的实验中会发现并没有MVC中M层的体现,是因为C层即充当了C也充当了M层,这样设计并不合理,所以需要分离出来。

创建一个service包,包中写一个接口,并且实现这个接口:

代码:

package service;
import domain.UserForm;
public interface UserService {
	boolean login(UserForm user);
	boolean register(UserForm user);
}
package service;
import org.springframework.stereotype.Service;

import domain.UserForm;
//注解为一个服务
@Service
public class UserServiceImpl implements UserService{
	@Override
	public boolean login(UserForm user) {
		if("zhangsan".equals(user.getUname()) 
				&& "123456".equals(user.getUpass()))
			return true;
		return false;
	}
	@Override
	public boolean register(UserForm user) {
		if("zhangsan".equals(user.getUname()) 
				&& "123456".equals(user.getUpass()))
			return true;
		return false;
	}
}

在实现类的上方使用一个@service便将该类注明为一个服务

还需要在spring.xml配置文件中注册这个包

那么Controller中两个处理方法就可以简化了,可以改为:

	@RequestMapping("/login")
	public String login(UserForm user, HttpSession session, Model model) {
		if(userService.login(user)){
			session.setAttribute("u", user);
			logger.info("成功");
			return "main";//登录成功,跳转到main.jsp
		}else{
			logger.info("失败");
			model.addAttribute("messageError", "用户名或密码错误");
//		 等价于	request.setAttribute("k", Object); 
			return "login";
		}	
	}
	@RequestMapping("/register")
	public String register(){
		return "register";
	}
	/**
	 *处理注册
	 */
	@RequestMapping("/register1")
	public String register(@ModelAttribute("user") UserForm user) {
		if(userService.register(user)){
			
			logger.info("成功");
			return "login";
		}else{
	       logger.info("失败");

			return "register";
		}
	}

@ModelAttribute:

1、绑定请求参数到实体对象

在一个处理方法中参数中(@ModelAttribute(“user”)UserForm user)和(@ModelAttribute UserForm user),这两种语句都会创建一个UserForm类型的实例对象,但在model中存储的键值不同,第一种为user,因为已指明,第二种为userForm,因为没有指明键值,所以会以类名第一个首字母小写,转化为键值存储。

2、注解一个非请求的处理方法

当方法上以@ModelAttribute注明时,该方法将在Controller类的请求处理方法之前被调用。相当于一个过滤器的作用。

示例代码:

	@ModelAttribute  
    public void isLogin(HttpSession session) throws Exception {      
       if(session.getAttribute("user") == null){  
           throw new Exception("没有权限");  
       }  
    } 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值