继低配版的springmvc之后,我们写一个标准的springmvc。
在pom文件中,加入spring环境依赖。为了之后在jsp中好写代码,我还加入了jstl依赖:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ocean</groupId>
<artifactId>standard_springmvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
</dependencies>
</project>
web.xml中有较大的改变:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>standard_springmvc</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CharacterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
我们还是处理所有的.do请求,但是我们提前配置好了DispatcherServlet,这和在低配版springmvc中自己写DispatcherServlet相比就方便很多了。
我们还在DispatcherServlet中初始化了一个参数:contextConfigLocation。
这是DispatcherServlet的父类FrameworkServlet中的一个属性:
我们把spring配置文件的路径给它,这样web容器启动的时候,spring的配置文件就会被读到。
另外,我们处理了从客户端发来中文的问题——只需要配一个过滤器就行了。
那么spring.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:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="com.ocean"></context:component-scan>
<!-- 试图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
首先是组件扫描,这是自动扫描,com.ocean下的所有类都会被扫描到,然后加了@Controller等注解的类spring容器就会为你管理。
下面是试图解析器,DispatcherServlet会在ViewResolver的帮助下展示页面。
看一下标准springmvc的目录结构:
我们还是展示最基本的注册登录功能。
为了封装用户的注册登录信息,我们写了一个User类:
package com.ocean.entity;
public class User {
private String username;
private String password;
private String email;
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + ", email=" + email + "]";
}
}
从注册开始。
因为请求会被Controller处理,所以我们要先找到Controller:
package com.ocean.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ocean.entity.User;
import com.ocean.service.LoginService;
import com.ocean.service.RegisterService;
@RequestMapping("user")
@Controller()
public class UserController {
@RequestMapping(value = {"reg.do", "register.do"})
public String reg() {
return "reg";
}
@RequestMapping("handle_reg.do")
public String tologin(User user, HttpServletRequest request, ModelMap modelMap) {
Integer result = new RegisterService().regService(user, request);
if (result == 0) {
modelMap.addAttribute("errorMsg", "输入不能为空!");
return "error";
} else if (result == 2) {
modelMap.addAttribute("errorMsg", "密码必须为8至10位的数字、大小写英文字母!");
return "error";
} else {
return "redirect:login.do";
}
}
@RequestMapping("login.do")
public String login(User user) {
return "login";
}
@RequestMapping("handle_login.do")
public String handle_login(User user,HttpServletRequest request,ModelMap modelMap) {
Integer result = new LoginService().loginService(user, request);
if(result == 1) {
return "redirect:index.do";
}else {
modelMap.addAttribute("errorMsg", "登录信息有误!");
return "error";
}
}
@RequestMapping("index.do")
public String show_index() {
return "index";
}
}
在UserController上加@RequestMapping("user")
,那么等下我们发起请求的时候就要把路径user加上。
@RequestMapping(value = {"reg.do", "register.do"})
public String reg() {
return "reg";
}
比如你发起了xxx/user/reg.do或者是xxx/user/register.do的请求(http://localhost:8088/standard_springmvc/user/reg.do),我们的reg()方法就会处理,然后返回字符串"reg"。于是DispatcherServlet就向用户展示了页面reg.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="handle_reg.do" method="post">
<fieldset>
<legend>注册</legend>
用户名:<input type="text" name="username" /><br> 密码:<input
type="password" name="password" /><br>
邮箱:<input type="text" name="email">
<input type="submit" value="提交"/>
</fieldset>
</form>
</body>
</html>
随便输一点内容,点击提交,注解值为handle_reg.do的方法将处理注册业务。
@RequestMapping("handle_reg.do")
public String tologin(User user, HttpServletRequest request, ModelMap modelMap) {
Integer result = new RegisterService().regService(user, request);
if (result == 0) {
modelMap.addAttribute("errorMsg", "输入不能为空!");
return "error";
} else if (result == 2) {
modelMap.addAttribute("errorMsg", "密码必须为8至10位的数字、大小写英文字母!");
return "error";
} else {
return "redirect:login.do";
}
}
spring自动把你注册时输入的姓名、密码和邮箱封装到了User当中。
我们当然要处理用户的注册,因为不是所有的注册都是合法的。
我们用RegisterService中的方法regService来处理。
package com.ocean.service;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ocean.entity.User;
@Service
public class RegisterService {
public Integer regService(User user, HttpServletRequest request) {
String username = user.getUsername();
String password = user.getPassword();
String email = user.getEmail();
System.out.println("注册的user:" + user);
if (StringUtils.isEmpty(username.replace(" ", "")) ||
StringUtils.isEmpty(password.replace(" ", ""))
|| StringUtils.isEmpty(email.replace(" ", ""))) {
return 0;
}
boolean flag = false;
flag = Pattern.matches("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$", password);
if (flag) {
request.getSession().setAttribute("username", user.getUsername());
request.getSession().setAttribute("password", user.getPassword());
request.getSession().setAttribute("email", user.getEmail());
return 1;
} else {
return 2;
}
}
}
把用户输入的username、password、email全部拿出来,要是有为空的,就返回0;在三者都不为空的情况下,要是密码符合要求的(8到10位的数字、大小写字母),就返回1(通过注册),否则就返回2。
我们一定要将信息返回给Controller处理,由Controller决定下一步该做什么(是展示页面,还是调用别的service)。
若是用户通过注册,我们将其信息存到session中,以便等下取出来:
request.getSession().setAttribute("username", user.getUsername());
request.getSession().setAttribute("password", user.getPassword());
request.getSession().setAttribute("email", user.getEmail());
在Controller里,我们用ModelMap绑定错误信息,并传给error.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>
错误:${errorMsg }
</body>
</html>
符合规则,就去登录return "redirect:login.do";
@RequestMapping("login.do")
public String login() {
return "login";
}
重定向后,由login方法处理,并返回"login",然后展示页面:
<%@ 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="handle_login.do" method="post">
<fieldset>
<legend>登录</legend>
用户名:<input type="text" name="username" /><br> 密码:<input
type="password" name="password" /><br>
邮箱:<input type="text" name="email">
<input type="submit" value="提交"/>
</fieldset>
</form>
</body>
</html>
按提交之后,我们让handle_login.do处理:
@RequestMapping("handle_login.do")
public String handle_login(User user,HttpServletRequest request,ModelMap modelMap) {
Integer result = new LoginService().loginService(user, request);
if(result == 1) {
return "redirect:index.do";
}else {
modelMap.addAttribute("errorMsg", "登录信息有误!");
return "error";
}
}
同样的,登录也不是一帆风顺的,我们让LoginService一一核对信息。
package com.ocean.service;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;
import com.ocean.entity.User;
@Service
public class LoginService {
public Integer loginService(User user,HttpServletRequest request) {
String loginUsername = user.getUsername();
String loginPassword = user.getPassword();
String loginEmail = user.getEmail();
System.out.println("登录时输入的user:"+user);
String regUsername = (String) request.getSession().getAttribute("username");
String regPassword = (String) request.getSession().getAttribute("password");
String regEmail = (String) request.getSession().getAttribute("email");
if(loginUsername.equals(regUsername) && loginPassword.equals(regPassword)
&& loginEmail.equals(regEmail) ) {
return 1;
}else {
return 0;
}
}
}
我们拿到用户登录信息,并且取出注册时的信息,比较之后判断是否登录成功。
如果失败,还是进入error页面:
如果成功,就进入个人主页index页面。
@RequestMapping("index.do")
public String show_index() {
return "index";
}
index.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>主页</title>
</head>
<body style="font-size: 30px;">
<h1>欢迎来到您的主页!</h1>
<p>用户名:${username }</p>
<p>密码:${password }</p>
<p>邮箱:${email }</p>
</body>
</html>
我们用El表达式取出session中的信息。
过程基本上就是这样。但是里面还有很多细节问题。
我们可以在不注册登录的情况下直接访问主界面。这当然是不合理的。
你可以这么修改index.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:if test="${username==null }">
<jsp:forward page="login.jsp"></jsp:forward>
</c:if>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>主页</title>
</head>
<body style="font-size: 30px;">
<h1>欢迎来到您的主页!</h1>
<p>用户名:${username }</p>
<p>密码:${password }</p>
<p>邮箱:${email }</p>
</body>
</html>
在最上面判断用户名是否为空,这的确能跳到登录页面,但这显然不够好:
登录页面的网址是xxx/user/index.do,这是有问题的。
你当然能用烦人的jsp语法解决:
<%-- <c:if test="${username==null }">
<jsp:forward page="login.jsp"></jsp:forward>
</c:if> --%>
<%
String username = (String)session.getAttribute("username");
if(username == null){
response.sendRedirect("login.do");
}
%>
如此问题就解决了。
不过,我们最好写个拦截器。
我们的思路是:必须要登录,才能进入主界面。
拦截器类:
package com.ocean.utils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class Interceptor implements HandlerInterceptor{
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// TODO Auto-generated method stub
String username = (String) request.getSession().getAttribute("username");
if(username == null) {
response.sendRedirect("login.do");
return false;
}
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
在spring.xml中配置拦截器:
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截路径 -->
<mvc:mapping path="/user/index.do"/>
<mvc:mapping path="/user/handle_login.do"/>
<!-- 例外路径 -->
<mvc:exclude-mapping path="/user/login.do"/>
<!-- 拦截器类 -->
<bean class="com.ocean.utils.Interceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>