1.Spring MVC依赖于Spring核心,实现了传统MVC三层架构
完整流程如下
可总结出 Spring MVC 的工作流程如下:
1.客户端请求提交到 DispatcherServlet。
2.由 DispatcherServlet 控制器寻找一个或多个 HandlerMapping,找到处理请求的 Controller。
3.DispatcherServlet 将请求提交到 Controller。
4.Controller 调用业务逻辑处理后返回 ModelAndView。
5.DispatcherServlet 寻找一个或多个 ViewResolver 视图解析器,找到 ModelAndView 指定的视图。
6.视图负责将结果显示到客户端。
DispatcherServlet、HandlerMapping、Controller 和 ViewResolver 是springMVC中比较重要4个接口,感兴趣可以查资料详细了解
2.创建SpringMVC项目
1.打开IDEA->new project->Maven 记得勾选create from archetype
直接点击到最后一步
2.创建完项目还缺少一些文件目录,需要建立缺少的文件夹
目录说明:
main/java 生产环境代码主目录
-com.mike 包名,根据情况建立
--common 公用类目录
--controller 控制器目录,处理客户端请求,调用service处理业务
--dao 数据访问对象查代码目录,主要是增删改
--entity 数据表实体类目录,与数据库表对应的类,属性与字段对应
--pojo 普通实体类目录,不需要与表属性对应
--service 服务类目录,主要是调用一个或多个dao
webapp 静态资源主目录
jsp jsp视图文件目录
web.xml文件 serlvet原生配置,在springmvc中主要是配置DispatcherServlet 来接管所有请求
springmvc-serlvet.xml文件 bean配置,配置视图解析器,及静态资源可见性,及使用@AutoWried自动注解时需要扫描的包目录
test/java 测试环境代码主目录
-com.mike 包名,根据情况建立
3.编写配置文件
1.在WEB-INF目录下找到web.xml 没有就新建
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>springMVC-demo1</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.在WEB-INF下新建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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--基于注解的注入需要配置扫描包-->
<context:component-scan base-package="com.mike"/>
<!-- annotation-driven用于简化开发的配置,注解DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter -->
<mvc:annotation-driven/>
<!--允许css目录下文件可见-->
<mvc:resources location="/css/" mapping="/css/**" />
<!-- 允许html目录下的所有文件可见 -->
<mvc:resources location="/html/" mapping="/html/**"/>
<!-- 允许image目录下的所有文件可见 -->
<mvc:resources location="/images/" mapping="/images/**"/>
<!--视图配置器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp"/>
</bean>
</beans>
3.SpringMVC常用的注解
注解在java中的作用简单可以理解为代码中带@特殊标记,这些标记有不同种类,功能也不同,注解是java的语法特性,用户可以自定义注解,jdk也自带一些注解,这两种注解都会被jvm处理
- javax.annotation.Resource包下的@Resource(name="bean_name") 自带注解,当一个构造方法,或setter,或属性被申明为@Resource注解时,容器会实例化其引用的对象实例,而无须手动实例化
- org.springframework.stereotype.Controller包下的@Controller,申明该类为控制器,当客户端请求到来,会被用来处理请求
- org.springframework.stereotype.Service包下的@Service ,申明该类为服务,可以在Controller调用该服务
- org.springframework.stereotype.Repository包下的@Repository,申明该类为dao及数据访问对象,可以该类中实现对数据库增删改查
- org.springframework.stereotype.Component 包下的@Component ,申明该类为普通的pojo类,及普通实体类
- org.springframework.beans.factory.annotation.Autowired包下的@AutoWired; 申明后,使用容器自动注解,容器会根据xml中配置的包路径,扫描该引用的实例,并绑定到该类中
- org.springframework.web.bind.annotation.RequestMapping下的@RequestMapping;申明后,将该方法与路由绑定,用户可以通过路由访问该方法
注意: 上述注解中 @Resource 和@AutoWired注解主要用来进行依赖注入,而当使用@AutoWried时,引用的类有多个实例时,建议使用@Qualifier注解,该注解基于name来查找实例,可以冲突
在springMVC中注入其他类基本上是利用spring核心的容器实现即
- setter注入,
- 构造方法注入
- 属性注入
下面简述一下使用三种方法注入
1.setter注入,推荐使用,当引用的对象可能会经常变化时使用
public class UserController {
public UserService userService;
@AutoWried
public void setUserService(UserService userService) { // 在类中申明要引用类的setter方法,容器会自动注入该引用的类实例
this.userService = userService
}
//使用userService 对象
}
2.构造方注入,也推荐使用,当引用的对象不经常变化时使用
public class UserController{
public UserService userService;
@AutoWried
UserController(UserService userService) { //在类的构造方法参数中申明要引用类的变量,容器会自动注入该引用的实例
this.userService = userService;
}
//使用userService对象
}
3.属性注入,该注入方式最简单,只需在引用的类属性上加入@AutoWried即可,但是不推荐使用该方法,spring官方也说明不推荐使用属性注入,具体原因可以查阅资料
public class UserController{
@AutoWired
public UserService userService;
//使用userService对象
}
4.完整例子
在controller目录下新建UserController类文件
package com.mike.controller;
import javax.servlet.http.HttpSession;
import com.mike.pojo.UserForm;
import com.mike.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
@Controller
@RequestMapping(value="/user")
public class UserController {
public UserService userService;
@Autowired
UserController(UserService userService) { //构造方法注入UserService实现类,当有多个UserService实现类使用@Qualifier注解
this.userService = userService;
}
// @Autowired
// public void setUserService(UserService userService) { // setter注入UserService实现类
// this.userService = userService;
// }
@RequestMapping(value = "/login")
public String login(UserForm user,HttpSession session,Model model) { //当表单name和UserForm的属性一致时会自动将表单值填入UserForm中
if(userService.login(user)) { //判断用户名和密码是否正确
session.setAttribute("user",user);
System.out.println("登陆成功");
return "main";
} else {
model.addAttribute("messageError","用户名或密码错误"); //当登陆失败提示信息,并跳转到登陆页面
System.out.println("登陆失败");
return "login";
}
}
@RequestMapping(value="/register")
public String register(UserForm user,Model model) {
if(userService.register(user)) {
System.out.println("注册成功");
return "login";
} else {
model.addAttribute("username",user.getUsername());//注册失败将原来用户名重新显示在文本框
System.out.println("注册失败");
return "register";
}
}
}
在pojo目录下新建UserForm类文件
package com.mike.pojo;
public class UserForm {
private String username;
private String password;
private String newPassword;
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 getNewPassword() {
return newPassword;
}
public void setNewPassword(String newPassword) {
this.newPassword = newPassword;
}
}
在service目录下建立UserService接口及UserService接口的实现类UserServiceImpl
package com.mike.service;
import com.mike.pojo.UserForm;
public interface UserService {
boolean login(UserForm user);
boolean register(UserForm user);
}
package com.mike.service;
import com.mike.pojo.UserForm;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
public boolean login(UserForm user) {
return "mike".equals(user.getUsername()) && "123".equals(user.getPassword());
}
public boolean register(UserForm user) {
return "mike".equals(user.getUsername()) && "123".equals(user.getPassword());
}
}
在jsp目录下分别新建login.jsp
<%--
Created by IntelliJ IDEA.
User: mike
Date: 2021/1/6
Time: 13:03
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<%@page isELIgnored="false" %> <!--应为默认的servlet1.2 el表达式是关闭的,需要启用-->
<title>登陆</title>
</head>
<body>
<form action="<%request.getContextPath();%>/user/login" method="post" name="loginForm">
<table>
<tr>
<td>姓名:</td>
<td><input class="textSize" type="text" name="username"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input class="textSize" type="password" name="password"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="登陆"/>
</td>
</tr>
</table>
${messageError}
</form>
</body>
</html>
register.jsp
<%--
Created by IntelliJ IDEA.
User: gaoyong
Date: 2021/1/6
Time: 13:03
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<%@page isELIgnored="false" %> <!--应为默认的servlet1.2 el表达式是关闭的,需要启用-->
<title>注册</title>
</head>
<body>
<form action="<%request.getContextPath();%>/user/register" method="post" name="registerForm">
<table>
<tr>
<td>姓名:</td>
<td><input class="textSize" type="text" name="username" value="${username}"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input class="textSize" type="password" name="password"/></td>
</tr>
<tr>
<td>确认密码:</td>
<td><input class="textSize" type="password" name="newPassword"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="注册"/>
</td>
</tr>
</table>
</form>
</body>
</html>
main.jsp
<%@ page import="com.mike.pojo.UserForm" %><%--
Created by IntelliJ IDEA.
User: gaoyong
Date: 2021/1/6
Time: 14:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆成功页面</title>
</head>
<body>
<% UserForm user = (UserForm)request.getSession().getAttribute("user");%>
<h1>当前登陆用户为:<%= user.getUsername() %></h1>
</body>
</html>
注意:控制器中如 login(UserForm user,HttpSession session,Model model)方法中的参数,user会在当页面的表单的name名和UserForm类中的属性一致时,自动填充到该类,而model参数会将我们写的信息返回到jsp页面
当我们访问http://localhost:8080/index/register 方法会看到注册表单register.jsp,输入mike,123,123 注册成功会跳转到登陆表单login.jsp,当我们再次输入mike,123登陆成功后会跳转到main.jsp会显示当前登陆的用户名