SpringMvc的Controller
代码是上一篇的累加!!!
1、基于注解的控制器
①、在基于注解 的控制器类中可以同时编写多个处理方法,进而可以处理多个请求的url,
这就允许将相关的操作编写在同一个控制器类中,从而减轻控制器类的数量,方便以后的维护。
②、基于注解的控制器不需要再文件配置文件中部署映射,仅需要使用RequestMapping注解一个方法
进行请求的处理。
1、Controller注解类型
在spring MVC中使用org.springframework.stereotype.Controller;注解来声明某个类的实例
是一个控制器。如:
package controller; import org.springframework.stereotype.Controller; @Controllerpublic class UserController {
...
}
在spring MVC中使用扫描机制找到对应的注解的控制器类
为了让控制类被spring MVC扫描到,需要在配置文件中使用spring-context
并且使用<context:component-scan/>元素指定控制器类的包。
如:
<?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:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd 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.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 注解 --> <!--使用扫描机制 --> <context:component-scan base-package="controller" />
<!--配置视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前缀 --> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--后缀--> <property name="suffix" value=".jsp"></property> </bean> </beans>
2、RequestMapping注解类型
使用org.springframework.web.bind.annotation.RequestMapping注解类型将请求与处理方法一一对应
①、方法级注解
package controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class UserController { @RequestMapping("/login") public String login(){ ... } ... }
作用是放在方法上的,注解的value属性将请求的URL映射到方法
value属性是RequestMapping注解的默认属性,若请求只用value一个属性,可以省略。
②、类级别注解
package controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import pojo.User; import javax.servlet.http.HttpSession; @Controller @RequestMapping("/user") public class UserController { //处理登陆 @RequestMapping("/login") public String login(User user, HttpSession session, Model model){ ... }
.....
}
在类级别注解下,控制器会将类中的所有方法都映射为类级别的请求。
在开发时,为了方便维护程序,建议使用类级别注解,将相关处理放在同一个控制器中。
3、编写请求处理方法
①、如果请求处理方法需要使用Servlet API类型,那么可以将这些类型作为请求处理方法的参数类型
如:
@Controller @RequestMapping("/user") public class UserController { //处理登陆 @RequestMapping("/login") public String login(HttpServletRequest req, HttpSession session, Model model){ req.setAttribute("req","req...set");
session.setAttribute("session","session...set");
....... } }
其中Model类型,是一个包含Map的Spring框架类型。
每次调用请求处理方法时spring MVC都将创建Model对象。
②、请求处理方法常见的返回类型
最常见的返回类型就是代表逻辑视图名称的String类型,除此之外,还有ModelAndView、Model、View以及其他任意的Java类型。
2、Controller接受请求参数最常见的方式
1、通过实体Bean接受请求参数
通过一个实体Bean来接收请求参数,适用于get和post提交请求的方式。
🐖:Bean的属性名必须和请求参数的名称相同。
代码进行测试:
工程从上一次的工程续写!!!!
①、创建首页
index.jsp
<%@ page pageEncoding="UTF-8" import="java.util.*" contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> 未注册的用户,请<a href="<%=request.getContextPath()%>/index/register">注册</a><br> 已注册的用户请<<a href="<%=request.getContextPath()%>/index/login">登陆</a> </body> </html>
2、配置文件
dispatcher-servlet.xml
<!-- 注解 --> <!--使用扫描机制 --> <context:component-scan base-package="controller" /> <!-- annotation-driven用于简化开发的配置, 注解:DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdapter --> <mvc:annotation-driven></mvc:annotation-driven> <!-- 使用resources过滤掉不需要dispatcherServlet的资源(静态资源、css、js、html....) 使用resources必须使用annotation-driven,否则resources元素会阻止任意控制器被调用 --> <!--允许css目录下所有文件可见 --> <mvc:resources ma pping="/css/**" location="/css/" ></mvc:resources> <!--允许html目录下所有文件可见 --> <mvc:resources mapping="/html/**" location="/html/" ></mvc:resources> <!--允许image目录下所有文件可见 --> <mvc:resources mapping="/image/**" location="/image/" ></mvc:resources> <!--配置视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前缀 --> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--后缀--> <property name="suffix" value=".jsp"></property> </bean>
③pojo类
public class User { private String uname; private String upass;private String reupass;
//setter getter
}
④、创建控制器的类
package controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/index") public class IndexController { @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping("/register") public String register(){ return "register"; } }
package controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import pojo.User; import javax.servlet.http.HttpSession; @Controller @RequestMapping("/user") public class UserController { //处理登陆 @RequestMapping("/login") public String login(User user, HttpSession session, Model model){ //注意这里将会对前端页面进行获取 System.out.println(user); if(user.getUname().equals("admin") && user.getUpass().equals("1")){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } } //处理注册 @RequestMapping("/register") public String register(User user,Model model){ if (user.getUname().equals("admin") && user.getUpass().equals("1")){ return "login"; }else { model.addAttribute("uname",user.getUname()); return "register"; } } }
⑤、创建页面视图
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <b>登陆</b> <form action="<%=request.getContextPath()%>/user/login" method="post"> <table border="1" bgcolor="#add8e6" align="center"> <tr> <td>姓名:</td> <td> <input type="text" name="uname" value="${uname}"> </td> </tr> <tr> <td>密码:</td> <td> <input type="text" name="upass" > </td> </tr> <tr> <td>确定密码:</td> <td> <input type="text" name="reupass" > </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="登陆"> </td> </tr> </table> </form> ${msg} </body> </html>
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/user/register" method="post" name="register">
<table border="1" bgcolor="#add8e6" align="center">
<tr>
<td>姓名:</td>
<td>
<input type="text" name="uname" value="${uname}">
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="text" name="upass" >
</td>
</tr>
<tr>
<td>确定密码:</td>
<td>
<input type="text" name="reupass" >
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="注册">
</td>
</tr>
</table>
</form>
</body>
</html>
⑥、测试
点击登陆:
按照上图的方案进行登陆:
这里成功对登陆进行了拦截!
同时可以参考后台的控制台对数据的捕捉
2、通过HttpServlet接受请求参数
对上述的类进行修改:
UserController .java
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/login") public String login(HttpServletRequest request,Model model){ //获取账户和密码 String uname = request.getParameter("uname"); String upass = request.getParameter("upass"); System.out.println(uname + "---" + upass); if(uname.equals("admin") && upass.equals("1")){ return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } } //处理注册 @RequestMapping("/register") public String register(User user,Model model){ if (user.getUname().equals("admin") && user.getUpass().equals("1")){ return "login"; }else { model.addAttribute("uname",user.getUname()); return "register"; } } }
测试:
点击登陆:
后台控制台的打印:
3、通过处理方法的形参接受请求参数
对上述的类进行修改:
UserController .java
//通过请求方法的形参
@RequestMapping("/login")
public String login(String uname,String upass,Model model){
//获取账户和密码
System.out.println(uname + "===" + upass);
if(uname.equals("admin") && upass.equals("1")){
return "main";
}else {
model.addAttribute("msg","账户或者密码错误!!!");
return "login";
}
}
按照上述的数据进行登陆测试,检查后端的打印情况
4、通过@PathVariable接受URL中的请求参数
UserController .java
//通过@PathVariable接受URL中的请求参数 //必须使用method属性 @RequestMapping(value = "/login/{uname}/{upass}",method = RequestMethod.GET) public String login(@PathVariable String uname,@PathVariable String upass, Model model){ //获取账户和密码 System.out.println(uname + "===" + upass); System.out.println(uname + "---" + upass); if(uname.equals("admin") && upass.equals("1")){ return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } }
访问如下地址:
5、通过@RequestParam接受请求参数
UserController .java
@RequestMapping(value = "/login") public String login(@RequestParam String uname, @RequestParam String upass, Model model){ //获取账户和密码 System.out.println(uname + "===" + upass);if(uname.equals("admin") && upass.equals("1")){ return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } }
测试数据
后台检验:
6、通过@ModelAttribute接受请求参数
@ModelAttribute注解放在处理方法的形参上时,用于将多个请求参数封装到一个实体对象中,从而简化数据的绑定流程
而自动暴露为模型数据,在视图页面展示时使用。
@ModelAttribute注解接受请求参数适用于get/pos提交方式
UserController .java
//@ModelAttribute @RequestMapping(value = "/login") public String login(@ModelAttribute("user") User user,HttpSession session,Model model){ System.out.println(user); if(user.getUname().equals("admin") && user.getUpass().equals("1")){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } }
测试数据:
后台打印:
3、重定向与转发
重定向是将用户从当前处理的请求重定向到另一个视图或者处理请求,以前的请求中存放的信息全部失效,并且
进入一个新的request作用域。
转发是将用户对当前页面的请求转发给另一个视图或者处理请求,以前的request中存放的信息不会失效。
转发是服务器行为,重定向是客户端行为。
转发过程:
客户浏览器发送http请求,Web服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发
动作,将目标资源发送给客户;在这里转发的路径必须是web容器下的url,其不能完成向其他的web路径上,
中间传递的是自己的容器内的request。客户浏览器的地址栏中显示的仍然是其第一次访问时的路径,也就是
说客户是感觉不到服务器做了请求的转发。转发行为是浏览器制作了一次访问的请求。
重定向过程:
客户浏览器发送http请求,web服务器接受请求后发送302状态代码响应及时对应新的location给客户浏览器,
客户浏览器发现是302响应,则自动再发送一个新的http请求,请求URL是新的location地址,服务器根据此
请求寻找资源并发送给客户。在这里location可以重定向到任意的url,既然是浏览器重新发送了请求,那么就
没什么request传递的概念了,在客户浏览器的地址栏中显示的是其重定向的路径,客户可以观察到地址的变化,
重定向行为是浏览器做了至少两次访问请求。
spring MVC框架中,控制器默认处理方法的return语句就是转发的实现,只不过转发的是视图!!!
index.jsp
<body> 未注册的用户,请<a href="<%=request.getContextPath()%>/index/register">注册</a><br> 已注册的用户请<<a href="<%=request.getContextPath()%>/index/login">登陆</a><br> 请求转发:<a href="<%=request.getContextPath()%>/index/forward">请求转发</a><br> 重定向:<a href="<%=request.getContextPath()%>/index/redirect">重定向</a><br> </body>
IndexController .java
@Controller @RequestMapping("/index") public class IndexController { @RequestMapping("/login") public String login(){ return "login"; } @RequestMapping("/register") public String register(){ return "register"; }
@RequestMapping("/redirect") public String redirect(){ return "forward: /index/login"; } @RequestMapping("/forward") public String forward(){ return "redirect:/index/register"; } }
转发使用:forward
重定向:redirect
4、应用@Autowired进行依赖注入
Spring MVC是一个非常优秀的MVC框架,它具有依赖注入的特点。
可以使用@Autowired注解将依赖注入到一个属性或者方法。
如:
@Autowired
public UserService userService;
spring MVC为了能被作为依赖注入,类必须使用@Service注解注明为@Service(一个服务)
还需要在配置文件中进行扫描<context:component-scan base-package="包" />元素进行扫描以来的基本包。
UserService.java
package service; import pojo.User; public interface UserService { boolean login(User user); boolean register(User user); }
UserServiceImp.java
package service; import org.springframework.stereotype.Service; import pojo.User; @Service public class UserServiceImp implements UserService { @Override public boolean login(User user) { if ("admin".equals(user.getUname()) && "1".equals(user.getUpass())){ return true; }else { return false; } } @Override public boolean register(User user) { if ("admin".equals(user.getUname()) && "1".equals(user.getUpass())){ return true; }else { return false; } } }
UserController.java
@Controller @RequestMapping("/user") public class UserController { @Autowired private UserServiceImp userServiceImp; //测试@Autowire @RequestMapping("/login") public String login(User user, HttpSession session, Model model){ System.out.println(user); if (userServiceImp.login(user)){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } }
}
dispatcher-servlet.xml
<context:component-scan base-package="service"/>
测试:
进行登陆测试:
后台数据打印:
对于依赖注入在开发的时候经常使用,所以作为java工程师,是必须要进行掌握的!!!
5、@ModelAttribute
@ModelAttribute注解类型可经常实现一下两个功能:
①、绑定请求参数到实体对象(表单的命令对象)
//@ModelAttribute @RequestMapping(value = "/login") public String login(@ModelAttribute("user") User user,HttpSession session,Model model){ System.out.println(user); if(user.getUname().equals("admin") && user.getUpass().equals("1")){ session.setAttribute("user" ,user); return "main"; }else { model.addAttribute("msg","账户或者密码错误!!!"); return "login"; } }
上述有测试和相关截图!!!
②、注解一个非请求的处理方法
@ModelAttribute注解的方法将在每次调用该控制器类的请求处理方法前被调用。
这种特性可以用来控制登陆的权限。
BaseController .java
public class BaseController { @ModelAttribute public void isLogin(HttpSession session) throws Exception { if (session.getAttribute("user") == null){ throw new Exception("没有权限!"); } } }
ModelAttributeController .java
@Controller @RequestMapping("/admin") public class ModelAttributeController extends BaseController { @RequestMapping("/add") public String add(){ return "main"; } }
测试:
在该类中,add方法请求处理时,首先调用父类BaseController中的方法进行判断登陆权限。