SpringMVC(精簡) 一、SpringMVC介紹 1.什麼是MVC 是一種軟體架構的思想,將軟體按照模型、視圖、控制器來劃分 **M: **Model,模型層,指工程中的JavaBean,作用是處理數據 JavaBean 一類稱為實體類Bean:專門存儲業務數據的,如 Student、User ...
SpringMVC(精簡)
一、SpringMVC介紹
1.什麼是MVC
是一種軟體架構的思想,將軟體按照模型、視圖、控制器來劃分
- **M: **Model,模型層,指工程中的JavaBean,作用是處理數據
- JavaBean
- 一類稱為實體類Bean:專門存儲業務數據的,如 Student、User 等
- 一類稱為業務處理 Bean:指 Service 或 Dao 對象,專門用於處理業務邏輯和數據訪問。
- JavaBean
- **V: **View,視圖層,指工程中的html或jsp等頁面,作用是與用戶進行交互,展示數據
- **C: **Controller,控制層,指工程中的servlet,作用是接收請求和響應瀏覽器
MVC工作流程: 用戶通過視圖層發送請求到伺服器,在伺服器中請求被Controller接收,Controller調用相應的Model層處理請求,處理完畢將結果返回到Controller,Controller再根據請求處理的結果找到相應的View視圖,渲染數據後最終響應給瀏覽器
2.什麼是SpringMVC
是Spring的一個後續產品,是Spring的一個子項目
SpringMVC 是 Spring 為表述層開發提供的一整套完備的解決方案。目前業界普遍選擇了 SpringMVC 作為 Java EE 項目表述層開發的首選。
三層架構:表述層(或表示層)、業務邏輯層、數據訪問層,表述層表示前臺頁面和後臺servlet
3.SpringMVC的優點
- 輕量級,基於MVC框架
- 易上手,易理解,功能強大
- 具備IOC和AOP
- 完全基於註解開發
二、工程創建
1.開發環境
idea:2019.3.5
tomcat:9.0.59
Spring:5.3.22
Maven:3.6.1
2.基於註解的SpringMVC框架開發步驟總結
- 新建項目(可以直接選擇webapp的模板)
- 補全目錄
- 修改pom.xml,添加SpringMVC和Servlet依賴
- 添加springmvc.xml配置文件,指定包掃描,添加視圖解析器
- 刪除web.xml文件,新建web.xml(版本過低有些功能不支持)
- web.xml中註冊springmvc框架
- webapp下新建admin目錄,在目錄下新建main.jsp頁面,刪除index.jsp再添加index.jsp頁面
- 開發控制器(Servlet)
- 添加tomcat測試功能
實例
DemoAction.java
package com.xust.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DemoAction {
@RequestMapping("/demo.action")
public String demo(){
System.out.println("伺服器被訪問到了。。。。。");
return "main"; //直接跳到/admin/mian.jsp頁面
}
}
springmvc.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"
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">
<!--添加包掃描-->
<context:component-scan base-package="com.xust.controller"></context:component-scan>
<!--添加視圖解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置首碼-->
<property name="prefix" value="/admin/"></property>
<!--配置尾碼-->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--註冊SpringMVC框架-->
<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:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.xust</groupId>
<artifactId>spring_001_demo</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--添加SpringMVC的依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!--添加servlet依賴-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!--資源文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/demo.action">訪問伺服器</a>
</body>
</html>
三、RequestMapping註解
將請求和處理請求的控制器方法關聯起來,建立映射關係。
SpringMVC 接收到指定的請求,就會來找到在映射關係中對應的控制器方法來處理這個請求。
此註解加在方法前,可以為此方法註冊一個可以訪問的名稱(路徑)。
此註解加在類前,相當於虛擬路徑,對不同類進行區分
如:我在前面例子中類名前加@RequestMapping("/zar"),那麼index.jsp中就要改為
${pageContext.request.contextPath}/zar/demo.action
- 此註解可區分Get請求和Post請求
區分請求舉例
<form action="${pageContext.request.contextPath}/req.action" method="get">
<input type="submit" value="提交">
</form>
package com.xust.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class ReqAction {
@RequestMapping(value = "/req.action",method = RequestMethod.GET)
public String req(){
System.out.println("我是處理get請求的。。。。。。。。。。");
return "main";
}
@RequestMapping(value = "/req.action",method = RequestMethod.POST)
public String req1(){
System.out.println("我是處理post請求的。。。。。。。。。。");
return "main";
}
}
四、五種數據提交方式的優化
1.單個數據提交
自動註入並且類型轉換
<form action="${pageContext.request.contextPath}/one.action">
姓名:<input name="myname"><br>
年齡:<input name="myage"><br>
<input type="submit" value="提交">
</form>
package com.xust.controller;
import com.xust.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DataSubmitAction {
@RequestMapping("/one.action")
public String one(String myname,int myage){ //自動註入並且類型轉換
System.out.println("myname="+myname+",myage="+(myage+100));
return "main";
}
}
2.對象封裝提交數據
保證jsp中的name和類中的成員變數名稱相同
在提交請求中,保證請求參數的名稱與實體類中成員變數名稱一致,則可以自動提交數據,自動類型轉換,自動封裝數據到對象中。
<h2>2.對象封裝數據提交</h2>
<form action="${pageContext.request.contextPath}/two.action">
姓名:<input name="name"><br>
年齡:<input name="age"><br>
<input type="submit" value="提交">
</form>
package com.xust;
public class Users {
private String name;
private int age;
public Users(){}
public Users(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Users{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.xust.controller;
import com.xust.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DataSubmitAction {
@RequestMapping("/two.action")
public String two(Users u){
System.out.println(u);
return "main";
}
}
3.動態占位符提交
僅限於超鏈接或地址欄提交數據
一杠一值,一杠一大括弧,使用註解來解析
<h2>3.動態占位符提交</h2>
<a href="${pageContext.request.contextPath}/three/張三/22.action">動態提交</a>
package com.xust.controller;
import com.xust.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DataSubmitAction {
@RequestMapping("/three/{name}/{age}.action")
public String three(
@PathVariable
String name,
@PathVariable
int age){
System.out.println("name="+name+",age="+(age+100));
return "main";
}
}
//如果@RequestMapping中是{uname},下邊可以用@PathVariable(“uname)
4.映射名稱不一致
提交請求參數與action方法的形參名稱不一致,使用註解@RequestParam來解析
<h2>4.參數名稱不一致</h2>
<form action="${pageContext.request.contextPath}/four.action">
姓名:<input name="name"><br>
年齡:<input name="age"><br>
<input type="submit" value="提交">
</form>
package com.xust.controller;
import com.xust.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class DataSubmitAction {
@RequestMapping("/four.action")
public String four(
@RequestParam("name")
String uname,
@RequestParam("age")
int uage){
System.out.println("uname="+uname+",uage="+(uage+100));
return "main";
}
}
5.手工提取數據
<h2>5.手工提取數據</h2>
<form action="${pageContext.request.contextPath}/five.action">
姓名:<input name="name"><br>
年齡:<input name="age"><br>
<input type="submit" value="提交">
</form>
package com.xust.controller;
import com.xust.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class DataSubmitAction {
@RequestMapping("/five.action")
public String five(HttpServletRequest request){
String name=request.getParameter("name");
int age=Integer.parseInt(request.getParameter("age"));
System.out.println("name="+name+",age="+(age+100));
return "main";
}
}
五、中文編碼過濾器配置
在web.xml最前面加如下配置
<!--中文編碼過濾器配置-->
<filter>
<filter-name>encode</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--
配置參數
private String encoding;
private boolean forceRequestEncoding;
private boolean forceResponseEncoding;
-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
六、action方法返回值
-
**String: **客戶端資源地址,自動拼接首碼和尾碼,還可以屏蔽自動拼接字元串,可以指定返迴路徑。
-
**Object: **返回json格式對象,自動將對象或集合轉為json,使用jackson工具進行轉換,必須添加jackson依賴,一般用於ajax請求。
-
**void: **無返回值,一般用於ajax請求。
-
**基本數據類型: **用於ajax請求。
-
**ModelAndView: **返回數據和視圖對象,現在用的很少。
七、ajax請求返回學生集合
- 添加jackson依賴
- 在webapp目錄下新建js目錄,添加jQuery函數庫
- 在index.jsp導入函數庫
- 在action上添加註解@ResponseBody,用來處理ajax請求
- 在springmvc.xml添加註解驅動< mvc:annotationdriven/ >,它用來解析@ResponseBody註解
八、請求轉發和重定向
轉發可以攜帶數據,重定向不行
redirect和forward都可以屏蔽前尾碼,但前者在重定向時使用,地址欄發生變化,後者在轉發時使用,地址欄不變
1.請求轉發頁面(預設)
地址欄不變
<a href="${pageContext.request.contextPath}/one.action">1.請求轉發頁面(預設)</a>
@Controller
public class StudentListAction {
@RequestMapping("/one.action")
public String one(){
return "main"; //預設是請求轉發,使用視圖解析器拼接首碼尾碼進行頁面跳轉
}
}
2.請求轉發action
地址欄不變
<a href="${pageContext.request.contextPath}/two.action">2.請求轉發action</a>
@Controller
public class StudentListAction {
@RequestMapping("/two.action")
public String two(){
//forward可以屏蔽首碼和尾碼字元串的拼接
return "forward:/other.action";
}
}
@Controller
public class OtherAction {
@RequestMapping("/other.action")
public String other(){
return "main";
}
}
3.重定向頁面
地址欄變為.../admin/main.jsp
<a href="${pageContext.request.contextPath}/three.action">3.重定向頁面</a>
@Controller
public class StudentListAction {
@RequestMapping("/three.action")
public String three(){
//redirect可以屏蔽首碼和尾碼字元串的拼接
return "redirect:/admin/main.jsp";
}
}
4.重定向action
地址欄變為.../other.action
<a href="${pageContext.request.contextPath}/four.action">4.重定向action</a>
@Controller
public class StudentListAction {
@RequestMapping("/four.action")
public String four(){
//redirect可以屏蔽首碼和尾碼字元串的拼接
return "redirect:/other.action";
}
}
@Controller
public class OtherAction {
@RequestMapping("/other.action")
public String other(){
return "main";
}
}
九、SpringMVC預設參數類型
不需要創建,直接拿來用
- HttpServletRequest
- HttpServletResponse
- HttpSession
- Model
- Map
- ModelMap
Model、Map、ModelMap和Request一樣,都使用請求作用域進行數據傳遞,所以伺服器端的跳轉必須是請求轉發。
預設參數傳遞實例
index.jsp
<a href="${pageContext.request.contextPath}/data.action?name=zar">訪問伺服器進行數據攜帶跳轉</a>
main.jsp
<h2>顯示數據</h2>
${requestStudent}<br>
${sessionStudent}<br>
${modelStudent}<br>
${mapStudent}<br>
${modelStudent}<br>
上面是從action傳來的,從index.jsp傳來的數據name為${param.name}
Student.java
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
DataAction.java
@Controller
public class DataAction {
@RequestMapping("/data.action")
public String data(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model,
Map map,
ModelMap modelMap
){
//做一個數據傳到main.jsp
Student stu1=new Student("張三",21);
//傳遞數據
request.setAttribute("requestStudent",stu1);
session.setAttribute("sessionStudent",stu1);
model.addAttribute("modelStudent",stu1);
map.put("mapStudent",stu1);
modelMap.addAttribute("modelStudent",stu1);
return "main";
}
}
十、日期處理
1.日期的提交處理
(1)單個日期處理
要使用DataTimeFormat,此註解必須搭配springmvc.xml中的<mvc:annotationdriven >標簽。
可以在方法參數上使用,也可以在類中成員變數的setXXX()方法或屬性定義上使用,但是這種方法在每個用到日期類型的地方都要添加一次,比較麻煩,在下麵只演示第一種情況。
<form action="${pageContext.request.contextPath}/mydate.action">
日期:<input type="date" name="mydate"><br>
<input type="submit" value="提交">
</form>
@Controller
public class MyDateAction {
SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd");
@RequestMapping("/mydate.action")
public String mydate(
@DateTimeFormat(pattern = "yyyy-MM-dd") //將String註入給Date
Date mydate){
System.out.println(mydate);
System.out.println(sf.format(mydate));
return "show";
}
}
(2)類中全局日期處理
不使用@DateTimeFormat註解,使用@InitBinder註解,不需要綁定<mvc:annotationdriven >驅動
@Controller
public class MyDateAction {
SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd"); //固定格式
//註冊一個全局的日期處理的註解
@InitBinder
public void intiBinder(WebDataBinder dataBinder){
dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sf,true));
}
@RequestMapping("/mydate.action")
public String mydate(Date mydate){
System.out.println(mydate);
System.out.println(sf.format(mydate));
return "show";
}
}
2.日期的顯示處理
如果是單個日期對象,直接轉為好看的字元串進行顯示
如果是List中的實體類對象的成員變數是日期類型,則必須用jstl進行顯示
步驟:添加依賴Jstl,頁面上導入標簽庫,使用標簽顯示數據
(1)在Json文件中日期顯示
在類中成員getXXX()方法上使用註解@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
(2)Jsp頁面的日期顯示
添加依賴
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
jsp導入標簽庫
<%--導入jstl核心標簽庫--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--導入jstl格式化標簽庫--%>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
實例
<h2>集合</h2>
<table width="800px" border="1">
<tr>
<th>姓名</th>
<th>生日</th>
</tr>
<c:forEach items="${list}" var="stu">
<tr>
<th>${stu.name}</th>
<th>${stu.birthday}----- <fmt:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd"></fmt:formatDate></th>
</tr>
</c:forEach>
</table>
public class Users {
private String name;
private Date birthday;
public Users() {
}
public Users(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Users{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}';
}
}
@Controller
public class MyDateAction {
SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd"); //固定格式
@RequestMapping("/datelist.action")
public String datelist(HttpServletRequest request) throws ParseException {
Users u1=new Users("張三",sf.parse("2001-07-06"));
Users u2=new Users("李四",sf.parse("2001-07-07"));
Users u3=new Users("王五",sf.parse("2001-07-08"));
List<Users> list=new ArrayList<>();
list.add(u1);
list.add(u2);
list.add(u3);
request.setAttribute("list",list);
return "show";
}
}
WEB-INF目錄
此目錄下動態資源,不可直接訪問,只能通過請求轉發的方式進行訪問。
去尾碼
在web.xml中將
.action 改為/,訪問時網址欄可省略.action尾碼
登錄業務實現
<h2>登錄</h2>
<form action="${pageContext.request.contextPath}/login">
姓名:<input name="name"><br>
密碼:<input type="password" name="pwd"><br>
<input type="submit" value="登錄">
</form>
${msg}
@Controller
public class WebinfAction {
@RequestMapping("/showLogin")
public String showLogin(){
System.out.println("訪問login.jsp");
return "login";
}
//登錄的業務判斷
@RequestMapping("/login")
public String login(String name, String pwd, HttpServletRequest request){
if("zar".equalsIgnoreCase(name)&&"123".equalsIgnoreCase(pwd)){
return "main";
} else{
request.setAttribute("msg","用戶名或密碼錯誤");
return "login";
}
}
}
攔截器
上面雖然已經實現了登錄功能,但是通過修改地址欄可以跳過登錄,安全性不夠。
攔截器就是針對請求和響應添加額外的處理。在請求和響應過程中添加預處理,後處理和最終處理。
攔截器執行時機
- preHandle():請求被處理前操作
- postHandle:在請求被處理後,但結果還沒有被渲染之前操作,可以改變響應結果
- afterCompletion:所有請求響應結束後執行善後工作,清理對象,關閉資源
攔截器實現的兩種方式
-
繼承HandlerInterceptorAdapter的父類
-
實現HandlerInterceptor介面,推薦使用實現介面的方式
攔截器實現步驟
- 改造登錄方法,在session中存儲用戶信息,用於許可權驗證
- 開發攔截器功能,實現HandlerInterceptor介面,重寫preHandle()方法
- 在springmvc.xml中註冊攔截器
實例
<h2>登錄</h2>
<form action="${pageContext.request.contextPath}/login">
姓名:<input name="name"><br>
密碼:<input type="password" name="pwd"><br>
<input type="submit" value="登錄">
</form>
${msg}
@Controller
@RequestMapping("/showMain")
public String showMain(){
System.out.println("訪問main.jsp");
return "main";
}
@RequestMapping("/showLogin")
public String showLogin(){
System.out.println("訪問login.jsp");
return "login";
}
//登錄的業務判斷
@RequestMapping("/login")
public String login(String name, String pwd, HttpServletRequest request){
if("zar".equalsIgnoreCase(name)&&"123".equalsIgnoreCase(pwd)){
//在session中存儲用戶信息,用於許可權驗證
request.getSession().setAttribute("users",name);
return "main";
} else{
request.setAttribute("msg","用戶名或密碼錯誤");
return "login";
}
}
}
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//是否登錄過的判斷
if (request.getSession().getAttribute("users")==null){
//沒登錄
request.setAttribute("msg","請先登錄再訪問");
request.getRequestDispatcher("WEB-INF/jsp/login.jsp").forward(request,response);
return false;
}
return true;//放行請求
}
}
<!--註冊攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--映射要攔截的請求-->
<mvc:mapping path="/**"/>
<!--設置要放行的請求-->
<mvc:exclude-mapping path="/showLogin"/>
<mvc:exclude-mapping path="/login"/>
<!--配置具體攔截器功能的類-->
<bean class="com.xust.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>