博主每篇博文的浪漫主义
【我想在勇敢的少年时,去见每一座壮阔的雪山】 https://www.bilibili.com/video/BV1dT411P7Pw/?share_source=copy_web&vd_source=385ba0043075be7c24c4aeb4aaa73352
我想在勇敢的少年时,去见每一座壮阔的雪山
本片博文的学习笔记参照来源这里这个网站
Spring MVC有些地方也叫作Spring Web MVC,看名字就能知道这是一个表现层框架。在没有学习Spring MVC之类的框架的时候,一般会使用JavaEE中的servlet来接收和处理前台发送的请求,这种方式使用起来有一些不方便的地方,比如做一个增删改查,我们需要在servlet中编写判断逻辑来处理相应的增删改查的请求,这样代码显得冗余。
我们来看一下我这个项目的目录结构,
第一步:
创建一个项目,为了方便后续的操作,我们通过idea创建一个maven项目,通过maven来帮我们管理相关的jar文件,当然你也可以创建一个web项目,不过这样的话,就需要你手动的去下载Spring MVC相关的jar包了(麻烦)。
第二步:
导入相关Jar包,这里使用maven来帮我们管理,下面是pom.xml文件中的内容,目前只是写了一个非常简单的Spring MVC,所以只使用maven导入了spring-webmvc相关的包即可,一步一步的来嘛。
pom.xml文件中properties有什么用:
在标签内可以把版本号作为变量进行声明,后面dependency中用到版本号时可以用${变量名}的形式代替,这样做的好处是:当版本号发生改变时,只有更新properties标签中的变量就行了,不用更新所有依赖的版本号。
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
<spring-version>5.2.4.RELEASEspring-version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring-version}version>
dependency>
dependencies>
第三步:
注册Spring MVC的中央控制器DispatcherServlet,打开web.xml文件,在里面加入下面内容(我这里使用的是servlet4.0的版本的web.xml):
<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">
<servlet>
<servlet-name>springMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springMVCservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
web-app>
第四步:
maven项目中有个src/main/resources目录,在该目录下创建Spring MVC配置文件springmvc.xml,该xml配置文件可以任意命名,需要跟第三步中的init-param中的param-value保持一致即可。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
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
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
beans>
第五步:
创建一个类去实现org.springframework.web.servlet.mvc.Controller接口,通常我们称这样的类为Controller,它的作用有些类似之前学习的servlet,或者可以认为在Spring MVC里面,就是使用了Controller来代替了servlet,它提供了比servlet更加丰富的功能。
package controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloSpringMVC implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("hello", "hello first spring mvc");
mv.setViewName("/WEB-INF/jsp/first.jsp");
return mv;
}
}
第六步:
在springmvc.xml配置文件中注册第五步创建的Controller,添加下面内容:
<bean id="/hello.do" class="controller.HelloSpringMVC" />
第七步:
在WEB-INF目录中创建一个目录jsp,在这个jsp目录下创建一个first.jsp的文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
${hello}
body>
html>
第八步:
启动tomcat,然后在浏览器地址栏中输入:http://localhost:8080/hello.do
如果你看到网页中显示hello first spring mvc,那就说明第一个Spring MVC程序编写成功啦。
上面通过编写Controller和配置一些xml文件就实现了一个Spring MVC的程序,下面来分析下这些内容都表示什么意思。
在第三步中,我们在web.xml中注册了一个中央控制器DispatcherServlet,这个其实就是相当于注册了一个servlet,关于该servlet,我们添加了如下配置:
在第四步和第六步中我们创建和配置了springmvc.xml的文件,这个文件的命名是随意,所以需要在web.xml中的init-param标签进行配置。我们通过bean标签来注册一个Controller,即当请求的url是hello.do结尾的时候,中央控制器DispatcherServlet就会将请求分发到我们编写的HelloSpringMVC中。
在第五步中,我们编写了一个Controller,里面我们使用了ModelAndView类,分别调用了两个方法:
mv.addObject("hello", "hello first spring mvc");
表示我们向ModelAndView这个对象中添加一条数据,名字是hello,内容是hello first spring mvc,这个跟之前学习的map有些类似,实际上,addObject方法的底层就是一个map。在ModelAndView对象里面添加的数据,可以从jsp中获取,上面是直接使用EL表达式获取的数据。
mv.setViewName("/WEB-INF/jsp/first.jsp");
括号中的内容是要跳转的jsp的路径和文件名。
上面的流程只是表面的一个执行流程,通过这个简单的执行流程,我们可以看到大体上Spring MVC的工作方式,它的底层实际上就是一个servlet,主要依赖于其核心的中央控制器DispatcherServlet,请求和响应等一系列的工作都是由这个servlet来完成的,基于这样的原因,我们才会称DispatcherServlet为Spring MVC的中央控制器了。
在controller中我们在ModelAndView中的setViewName方法里面传入要跳转的jsp的路径和名字,如果有多个controller的话,需要在每个里面都编写路径和jsp的名字,这样的话比较繁琐 ,这时可以通过使用Spring MVC给我们提供的一个视图解析器来解决这个问题。
打开springmvc.xml的配置文件,在里面添加一个视图解析器:
<!-- 视图解释类 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
其中prefix表示前缀,即你的jsp所在的路径。
suffix表示后缀,即文件的后缀名。
之后来修改一下HelloSpringMVC中的内容,因为在springmvc.xml文件中已经配置了文件路径和后缀名了,所以将之前的:
mv.setViewName("/WEB-INF/jsp/first.jsp");
修改为:
mv.setViewName("first");
这样以后就不用再setViewName方法中写路径了,并且也方便日后的维护。
第一个注解式Spring MVC程序
在实际开发中,我们会创建很多Controller来满足业务方面的需求,这样就会导致一个问题,需要在springmvc.xml配置文件中配置大量的bean标签,这样就导致该配置文件变的臃肿起来,为了解决这个问题,spring MVC提供了一系列的注解,通过设置注解,可以使springmvc.xml配置文件变的简洁。
这里只是其中的一个。
使用注解编写spring MVC程序整体的步骤跟之前的差不多(不要忘记在web.xml文件中添加DispatherServlet),只不过有一些地方需要修改,在之前的spring MVC程序中添加下面内容。
大家可以新建一个springmvc项目,也可以在现在的项目上改一下,进行比较。
注册扫描器
在配置文件中我们只需要注册一个组件扫描器即可,其中base-package写上你的包名即可,下面这种写法表示会扫描controller下的所有类,该组件扫描器是spring中的内容,具体咱在spring中再讲解。
<!-- 注册组件扫描器 -->
<context:component-scan base-package="controller"/>
<!--注解驱动-->
<mvc:annotation-driven/>
注意:如果在你的springmvc.xml文件中配置了静态资源即使用了
mvc:resources
标签的话,那么需要在你的配置文件中配置注解驱动,添加下面内容:
<mvc:annotation-driven/>
如果没有添加注解驱动的话,你访问controller的时候会出现404错误。
在Java下的,controller包下创建一个AnnotationController类。
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class AnnotationController {
@RequestMapping("/test1")
public ModelAndView test1(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView();
mv.addObject("hello", "hello annotation");
mv.setViewName("annotation1");
return mv;
}
}
jsp的创建
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${hello}
</body>
</html>
在上面的示例中,我们创建了一个AnnotationController类,这类没有实现任何接口,只是在类名和方法上添加了两个注解:
@Controller:表示当前类为一个Controller
@RequestMapping:表示当前方法为Controller中的方法,该方法会处理请求,被注解的方法的名称是可以随意命名的。当有多个请求可以匹配该方法时,可以写上一个String类型的数组,如下示例中的test2方法。
@RequestMapping注解还可以定义在类上面,在上面的示例中,test1方法和test2方法中的url路径中都包含了/test,此时我们把这些相同的url抽取出来,放到类上的注解@RequestMapping中,此时可以称之为命名空间。
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
@RequestMapping("/test")//类名上的注解,命名空间namespace
public class TestController02 {
@RequestMapping("/test1")
public ModelAndView test1(HttpServletRequest request, HttpServletResponse response) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("hello", "hello annotation");
mv.setViewName("annotation1");
return mv;
}
@RequestMapping({"/test2", "/test3"})
public ModelAndView test2(HttpServletRequest request, HttpServletResponse response) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("name", "monkey1024");
mv.setViewName("annotation2");
return mv;
}
}
在@RequestMapping中有一个method属性,改属性可以设置接收请求的提交方式:
@RequestMapping(value="/test",method = RequestMethod.POST)
public ModelAndView test(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("hello", "test");
mv.setViewName("test1");
return mv;
}
上面的注解表示,只有当/test的请求的方式是post的时候才会执行当前方法,对于其他请求方式不进行处理。如果不写method属性的话,无论你是使用get或者post或者其他方式,它都会进行处理。
上面的RequestMethod是一个枚举类型,里面包含了大部分的提交方式。
示例,创建一个Controller,里面添加连个方法分别只处理get和post方式的请求:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller//表示当前类是一个controller
@RequestMapping("/test")//表示是一个命名空间namespace
public class TestController03 {
@RequestMapping(value="/requestGet",method = RequestMethod.GET)
public ModelAndView reqGet(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("method", "get请求");
mv.setViewName("get");
return mv;
}
@RequestMapping(value="/requestPost",method = RequestMethod.POST)
public ModelAndView reqPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("hello", "post请求");
mv.setViewName("post");
return mv;
}
}
页面中的内容:
<html>
<body>
<form action="/test/requestGet" method="get">
<input type="submit" value="get请求">
</form>
<br>
<form action="/test/requestPost" method="post">
<input type="submit" value="post请求">
</form>
</body>
</html>
请求中携带的参数
在实际开发中通过会在spring MVC的Controller里面接收表单提交过来的参数,这块代码该怎么去编写呢?
就是把前端的值传到后端?
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/regist1.do" method="post">
姓名:<input type="text" name="username"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
之后创建一个controller来接收这个表单提交的值:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class RegistController {
@RequestMapping("/regist1.do")
public ModelAndView regist1(String username, int age) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("username", username);
mv.addObject("age", age);
mv.setViewName("result");
return mv;
}
}
创建result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
用户名:${username}
<br>
年龄:${age}
</body>
</html>
在上面的controller中,我们在regist1方法后面的参数列表中写上了两个参数username和age,因为这两个参数与表单中input中的name一致,所以spring MVC会自动为其赋值,通过这种方式就可以在controller中获取表单提价的数据了。
此时你可能会发现一个问题,在之前我们写的controller中的方法参数列表里面我们都写上了request和response,而这里却没有写,其实这不会影响spring mvc的工作,也就是说在controller的方法里面,我们可以写多个参数,也可以一个都不写,不过spring mvc只会自动为以下五个参数进行自动赋值:
当前示例其实就是spring mvc将请求携带参数进行赋值,这样子我就可以直接获取表单提交的数据了。
在上面的示例中,倘若你输入了中文,那很有可能出现乱码问题,我们可以使用spring MVC为开发者提供的CharacterEncodingFilter来解决乱码问题,这个其实就是一个过滤器。我们需要在web.xml文件中进行配置,最好将其设置在其他过滤器之前,因为过滤器是按照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>
<!--强制指定字符编码,即如果在request中指定了字符编码,那么也会为其强制指定当前设置的字符编码-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*
这里可以通过springmvc的源码中看到forceEncoding如果设置为true的话,那么不论你是否在request中设置了字符编码,spring mvc都会强制将其字符编码设置为我们在web.xml文件中写的字符编码。
在实际开发中有可能会有这样的问题,就是表单中input的name和spring mvc方法中的参数名不一致,这时可以使用@RequestParam()注解来解决这个问题,这个注解中有三个属性:
value:指定请求参数的名称,即表单中input的name值。
name:同value,两者只能使用一个
required:指定该参数是否是必须传入的,boolean类型。若为 true,则表示请求中所携带的参数中必须包含当前参数。若为 false,则表示有没有均可。
defaultValue:指定当前参数的默认值。如果请求中没有该参数,则当前方法参数将取该默认值。
我们来看一下代码示例:
<form action="/regist1.do" method="post">
姓名:<input type="text" name="username"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
在controller的方法中的参数名与表单中的参数名不一致,使用@RequestParam:
@RequestMapping("/regist.do")
public ModelAndView regist(@RequestParam(name="username") String t_username, @RequestParam(name="age") int t_age) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("username", t_username);
mv.addObject("age", t_age);
mv.setViewName("result");
return mv;
}
设置defaultValue属性,当在jsp中没有填写年龄时,spring mvc会默认将其赋值为18
@RequestMapping("/regist.do")
public ModelAndView regist(@RequestParam(name="username") String t_username, @RequestParam(name="age",defaultValue = "18") int t_age) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("username", t_username);
mv.addObject("age", t_age);
mv.setViewName("result");
return mv;
}
设置required=true,此时系统会报出400的错误,因为请求参数中没有sex。
@RequestMapping("/regist.do")
public ModelAndView regist(@RequestParam(name="username") String t_username, @RequestParam(name="age",defaultValue = "18") int t_age, @RequestParam(required = true) String sex) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("username", t_username);
mv.addObject("age", t_age);
mv.setViewName("result");
return mv;
}
然后接下来我们使用对象来接收表单数据,这也是我们后面经常用到的。
在之前的接收表单提交参数的示例中有个问题,倘若表单中的参数较多的话,需要在controller的方法里面把这些参数都写上,这样就不太方便了,我们可以定义一个javabean,将表单中的参数都写到javabean的属性里面,然后将这个bean作为参数写到controller的方法中。
示例:
定义一个Student类,里面的属性名跟表单的name保持一致
对象里面包含属性
public class Student {
private String name;
private int 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;
}
}
然后我们再来写一下controller
定义Controller,在方法中将Student作为参数传入:
import com.monkey1024.bean.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class RegistController02 {
@RequestMapping("/regist")
public ModelAndView regist(Student student) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("name", student.getName());
mv.addObject("age", student.getAge());
mv.setViewName("result");
return mv;
}
}
通过这种方式,我们可以更方便的接收表单提交的数据了。
当请求中的参数是一个对象属性中的属性时,我们可以在表单中的name中写上对象属性.属性的方式进行处理。
定义一个School类:
package com.monkey1024.bean;
public class School {
private String schoolName;
private String address;
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
定义一个Student类,里面添加School对象属性:
package com.monkey1024.bean;
public class Student {
private String name;
private int age;
private School school;
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
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;
}
}
修改前台:
<form action="/regist" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
学校名称:<input type="text" name="school.schoolName"><br>
学校地址:<input type="text" name="school.address"><br>
<input type="submit" value="提交">
</form>
我们在修改一下RegistController02中的代码
import com.monkey1024.bean.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class RegistController02 {
@RequestMapping("/regist")
public ModelAndView regist(Student student) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("name", student.getName());
mv.addObject("age", student.getAge());
mv.addObject("schoolName", student.getSchool().getSchoolName());
mv.addObject("address", student.getSchool().getAddress());
mv.setViewName("result");
return mv;
}
}
我们来看一下result.jsp中的代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
用户名:${name}
<br>
年龄:${age}
<br>
密码:${password}
<br>
学校名称:${schoolName}
<br>
学校地址:${address}
</body>
</html>
Controller除了可以接收表单提交的数据之外,还可以获取url中携带的变量,即路径变量,此时需要使用@PathVariable注解来设置,其中包含下面几个属性。
创建Controller,注意@RequestMapping注解中的写法
import com.monkey1024.bean.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class RegistController03 {
@RequestMapping("/{username}/{age}/regist")
public ModelAndView regist(@PathVariable("username") String name,@PathVariable int age) throws Exception{
ModelAndView mv = new ModelAndView();
mv.addObject("name", name);
mv.addObject("age", age);
mv.setViewName("result");
return mv;
}
}
之后,在浏览器的地址栏里面直接输入:
localhost:8080/jack/19/regist
此时可以直接获取url中的jack和19的值。
这种方式在restful风格的url中使用较多,作者是这样说的。我感觉我太菜了。
救救就学到这里,博主的文章为什么没人看,虽然是抄作业吧,但我也是仔仔细细过了一遍的
提示:对于这篇学习笔记就暂时到这了,兄弟们加油
对于这篇学习笔记就暂时到这了,兄弟们加油
从现在做起,坚持下去,一天进步一小点,不久的将来,你会感谢曾经努力的你! |
如果又出错的,请各位友友指正。
新人报到,各位友友们,给我个三联(点赞,关注,收藏)