文章目录
什么是mvc
- MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
是将业务逻辑、数据、显示分离的方法来组织代码。 - MVC主要作用是降低了视图与业务逻辑间的双向耦合。
- MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作。
SpringMVC思想
操作流程
一、导包
1)核心容器模块
2)web模块
二、配置文件
IDEA初次配置时,需要在web.xml中 使用ALT+INS ,选择Servlet,搜索DispatcherServlet,导入前端控制器
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://xm
lns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--对应src路径下的spring配置文件-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- /*和/都是拦截所有请求,而/*的范围更大包括了jsp -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
src类路径下建立springxml文件,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 http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.akurisu">
</context:component-scan>
</beans>
三、写入对应控制类(类似servlet类)
index.jsp
<%--
Created by IntelliJ IDEA.
User: 86187
Date: 2021/6/11
Time: 16:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<a href="hello">helloworld</a>
</body>
</html>
first.jsp
<%--
Created by IntelliJ IDEA.
User: 86187
Date: 2021/6/12
Time: 8:48
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<p>你好世界</p>
</body>
</html>
SpringMVCTest(测试类)
package com.akurisu.servlet;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller //注解将该类视为控制类
public class SpringMVCTest {
@RequestMapping("/hello") //对应的请求方法,/也可以不写
public String helloTest(){
System.out.println("你好世界");
return "/WEB-INF/pages/first.jsp";
}
}
return语句可能每次都要写较长,因而我们使用视图解释器来缩短代码量
在springmvc.xml增加视图解释器 ,前缀为/WEB-INF/pages/,后缀为.jsp
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"></property>
<property name="prefix" value="/WEB-INF/pages/"></property>
</bean>
运行细节
一:运行流程;
1)、客户端点击链接会发送 http://localhost:8080/springmvc/hello 请求
2)、来到tomcat服务器; *
3)、SpringMVC的前端控制器收到所有请求
4)、来看请求地址和@RequestMapping标注的哪个匹配,来找到到底使用那个类的哪个方法来处理
5)、前端控制器找到了目标处理器类和目标方法,直接利用返回执行目标方法;
6)、方法执行完成以后会有一个返回值;SpringMVC认为这个返回值就是要去的页面地址
7)、拿到方法返回值以后;用视图解析器进行拼串得到完整的页面地址;
8)、拿到页面地址,前端控制器帮我们转发到页面;一个方法处理一个请求;
3、如果不指定文件位置,则默认启动的是/WEB-INF/dispatcherServlet(前端控制器名)-servlet.xml
4、 /:拦截所有请求,不拦截jsp页面,.jsp请求 /:拦截所有请求,拦截jsp页面,.jsp请求 处理.jsp是tomcat做的事;所有项目的小web.xml都是继承于大web.xml DefaultServlet是Tomcat中处理静态资源的? 除过jsp,和servlet外剩下的都是静态资源; index.html:静态资源,tomcat就会在服务器下找到这个资源并返回; 我们前端控制器的/禁用了tomcat服务器中的DefaultServlet
1)服务器的大web.xml中有一个DefaultServlet是url-pattern=/
2)我们的配置中前端控制器 url-pattern=/ 静态资源会来到DispatcherServlet(前端控制器)看那个方法的RequestMapping是这个index.html
3)为什么jsp又能访问;因为我们没有覆盖服务器中的JspServlet的配置
4) /* 直接就是拦截所有请求;我们写/;也是为了迎合后来Rest风格的URL地 址
@RequestMapping
细节详解
package com.akurisu.servlet;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/haha") //如果加入了这个注解,则相当于增加了一层路径,故而访问时访问地址为http://localhost:8080/haha/hello
@Controller //注解将该类视为控制类
public class SpringMVCTest {
@RequestMapping("/hello") //对应的请求方法,/也可以不写
public String helloTest(){
System.out.println("你好世界");
return "/WEB-INF/pages/first.jsp";
}
}
/*
* RequestMapping各种属性
* 1、value
* 2、method
* 限定发送请求的方法
* 例@RequestMapping(value = "/hello1",method = RequestMethod.POST)
* 限定请求的方法只能为post
* 3、params
* 规定请求的参数
* 例:@RequestMapping(value = "/hello1",params={"username","!pwd"})
* 限定的参数必须带有username,必须不带有pwd
* 4、headers
* 规定请求头
* 例
* 5、consumes:只接受内容类型是哪种的请求,规定请求头中的Content-Type
* 6、produces:告诉浏览器返回的内容类型是什么,给响应头中加上Content-Type:text/html;charset=utf-8
* */
ant风格的url
符号 | ? | * | ** |
---|---|---|---|
含义 | 匹配文件名中的一个字符 | 匹配文件名中任意个数的字符 | 匹配多层路径 |
示例
@Controller
public class SpringMVCTest {
@RequestMapping("/an?")
public String helloant(){
System.out.println("this is ant1");
return "first";
}
@RequestMapping("/ant")
public String helloant2(){
System.out.println("this is ant2");
return "first";
}
@RequestMapping("/*/ant")
public String helloant3(){
System.out.println("this is ant3");
return "first";
}
@RequestMapping("/**/ant")
public String helloant4(){
System.out.println("this is ant4");
return "first";
}
}
index.html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<a href="hello">helloworld</a>
<a href="ant">helloant</a>
<a href="anj">helloant1</a>
<a href="name/ant">helloant3</a>
<a href="name/mike/ant">helloant4</a>
</body>
</html>
点击helloant,结果输出this is ant2
点击helloant1,结果输出this is ant1
点击helloant3,结果输出this is ant3
点击helloant4,结果输出this is ant4
结果表明,当有更精确路径时,springmvc会使用更加精确的路径,例如在/ant和/an?之间选择了/ant
而本结果也很好的将各个符号的作用展现出来
@PathVariable
//路径上是可以有占位符的,占位符的语法是在任意路径上写一个变量名
@RequestMapping("/ant/{id}")
public String hellopath(@PathVariable("id")String id){
System.out.println("占位符的值为" + id);
return "first";
}
<a href="ant/mike">helloPath</a>
点击输出结果为 占位符的值为mike
从java中获取到了结果的值
REST
REST简介
REST是一种软件架构风格,或者说是一种规范,其强调HTTP应当以资源为中心,并且规范了URI的风格;规范了HTTP请求动作(GET/PUT/POST/DELETE/HEAD/OPTIONS)的使用,具有对应的语义。
REST推荐起名
/book/1 :GET----查询1号图书
/book/1 :PUT----更新1号图书
/book/1 :DELETE----删除1号图书
/book :POST-----添加图书
解决html不支持出了GET和POST请求问题
web.xml配置
web.xml配置
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
RestController
package com.akurisu.servlet;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* @author akurisu
* @create 2021-06-13 8:02
*/
@Controller
public class RestController {
@RequestMapping(value = "/book/?",method = RequestMethod.POST)
public String addBook(){
System.out.println("added succeessfully");
return "first";
}
@RequestMapping(value="/book/{did}",method=RequestMethod.DELETE)
public String deleteBook(@PathVariable("did")String id){
System.out.println("delete new id" + id);
return "first";
}
@RequestMapping(value="/book/{uid}",method=RequestMethod.PUT)
public String updateBook(@PathVariable("uid")String id){
System.out.println("update id=" + id);
return "first";
}
@RequestMapping(value="/book/{fid}",method=RequestMethod.GET)
public String findBook(@PathVariable("fid")String id){
System.out.println("find id=" + id);
return "first";
}
}
index.jsp
<a href="book/1">查询1号图书</a>
<form action="book/1" method="post">
<input type="submit" value="添加1号图书">
</form>
<form action="book/1"method="post">
<input name="_method" value="delete">
<input type="submit" valua="删除1号图书">
</form>
<form action="book/1"method="post">
<input name="_method" value="put">
<input type="submit" valua="更新1号图书">
</form>
高版本tomacat(8.0)以上会报
此时只需在转发页面添加isErrorPage=“true”
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
获取请求参数
获取普通的属性
一、默认方式获取请求参数,给方法参数上写一个和请求参数名相同的变量,这个变量就用来接受参数的值。
二‘、@RequestParam(“user”)
value:获取的请求参数的key
required:参数是否必须存在
defaultValue:如果没带默认值为
三、@RequestHeader:获取请求头中某个key的值
value:获取的请求参数的key
required:参数是否必须
defaultValue:如果没带默认值为
四、CookieValue(“JESSIONID”)
案例
package com.akurisu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author akurisu
* @create 2021-06-13 8:55
*/
@Controller
public class HelloController {
/*
* 测试默认方式获取请求参数
* */
@RequestMapping("/hhh")
public String requestTest(String username){
System.out.println("default method=" + username);
return "success";
}
/*
* 测试使用@RequestParam获取请求参数
* */
@RequestMapping("/hehe")
public String request(@RequestParam("user")String id){
System.out.println("user=" + id);
return "success";
}
/*
* 测试使用@RequestHeader获取请求头
* */
@RequestMapping("/gg")
public String tryTest(@RequestHeader("User-Agent") String head){
System.out.println("head=" + head);
return "success";
}
/*
* 测试使用@CookieValue获取cookie
* */
@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID")String cookie){
System.out.println("cookie=" + cookie);
return "success";
}
}
<body>
<a href="hhh?username=mike">helloUsername</a>
<a href="hehe?user=nike">helloUser</a>
<a href="gg">helloHead</a>
<a href="cookie">helloCookie</a>
</body>
依次点击四个超链接,控制台返回结果依次为
default method=mike
user=nike
head=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.41
cookie=949650E28143A07A24d344DDB95A7DF08
获取pojo属性
在SpringMVC中获取一个pojo类非常简单,只需要参数里为该类,且各属性名称相同即可
@RequestMapping("/student")
public String getStudent(Student student){
System.out.println(student);
return "success";
}
Student类
package com.akurisu.pojo;
/**
* @author akurisu
* @create 2021-06-13 12:03
*/
public class Student {
private String name;
private Integer studentId;
private String address;
private Teacher teacher;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", studentId=" + studentId +
", address='" + address + '\'' +
", teacher=" + teacher +
'}';
}
public Student(String name, Integer studentId, String address, Teacher teacher) {
this.name = name;
this.studentId = studentId;
this.address = address;
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
Teacher类
package com.akurisu.pojo;
/**
* @author akurisu
* @create 2021-06-13 12:03
*/
public class Student {
private String name;
private Integer studentId;
private String address;
private Teacher teacher;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", studentId=" + studentId +
", address='" + address + '\'' +
", teacher=" + teacher +
'}';
}
public Student(String name, Integer studentId, String address, Teacher teacher) {
this.name = name;
this.studentId = studentId;
this.address = address;
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
<form action="student" method="post">
姓名:<input type="text" name="name"><br>
学号:<input type="text" name="studentId"><br>
地址:<input type="text" name="address"><br>
<hr/>
教师姓名:<input type="text" name="teacher.name">
教师年龄:<input type="text" name="teacher.age">
<input type="submit">
</form>
输出结果为
Student{name=‘122’, studentId=122, address=‘122’, teacher=Teacher{name=‘122’, age=122}}
但中文会存在乱码问题,这会在下一节中解决相应问题
解决获取属性乱码问题
web.xml
<filter>
<filter-name>characterEncodingFilter</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>[
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
即可解决乱码问题
注意:字符编码filter一定要再其他filter之前,否则没法解决问题
数据输出
默认给页面传入数据的几种方法
可以使用map,model,modelMap来对页面进行数据输出,最终都是BindingAwareModelMap在工作,相当于给BindingAwareModelMap中放入的东西都会放入到请求域中,而一般情况下数据都是直接传入到request域内的。
示例
@Controller
public class OutputController {
@RequestMapping("/handle01")
public String handle01(Map map){
map.put("msg","mike");
return "success";
}
@RequestMapping("/handle02")
public String handle02(Model model){
model.addAttribute("msg","nike");
return "success";
}
@RequestMapping("/handle03")
public String handle03(ModelMap modelMap){
modelMap.addAttribute("msg","wohaochou");
return "success";
}
}
index.html
<a href="handle01">handle01</a>
<a href="handle02">handle02</a>
<a href="handle03">handle03</a>
success.html
<body>
<h1>跳转成功</h1>
pageContext: ${pageScope.msg}<br>
request: ${requestScope.msg}<br>
session: ${sessionScope.msg}<br>
application: ${applicationScope.msg}<br>
</body>
返回值可以使用modelAndView,启动对应的超链接后,编会在request域中加入msg,woshinima键值对,并且可以请求转发到success.jsp页面
@RequestMapping("/handle04")
public ModelAndView handle04(){
ModelAndView modelAndView=new ModelAndView("success");
modelAndView.addObject("msg","woshinima");
return modelAndView;
}
Session域中传入数据
可以在类前加入@SessionAttribute()来使得输出向Session域中传输数据