第一个MVC项目-HelloWorld
基本原理:
1、首先确认目录结构
确认目录结构
2、编写web.xml,主要是配置DispatcherServlet
web.xml
3、配置SpringMVC-servlet.xml
SpringMVC-servlet.xml
4、配置解析类
解析类
之后用户访问解析类内配置的名称,springmvc会自动调用在web.xml中配置的DispatcherServlet,DispatcherServlet首先会调用视图解析器根据设置的头尾拼接出完整资源名称,之后根据该名称查找对应的已注册的bean,找到后访问指定资源进行跳转
注意:若代码没出错依旧无法运行,检查idea配置问题
点击右上角
配置
查看当前web项目下是否有对应的lib包,若没有手动创建并导包
配置问题
使用注解配置
配置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">
<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-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
配置springmvc配置文件
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描指定包-->
<context:component-scan base-package="cn.yzx.controller"/>
<!--不处理静态资源-->
<mvc:default-servlet-handler/>
<!--
开启支持mvc注解驱动,要想使@RequestMappering注解生效,需要开启
处理器映射
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
处理器适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<mvc:annotation-driven/>自动注入了以上两个实例
-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
以上两个配置是死的,无序过多改动
接下来就很简单了,随意的创建一个类,随意的创建一个方法,使用两个注解完成所有操作
@Controller
public class helloController {
@RequestMapping("hello")
public String hello(Model model) {
model.addAttribute("msg","你好世界!!!"); //使用model共享数据
return "hello"; //在视图解析器配置了前置后置,所以这里直接返回资源的名称即可
}
}
补充:
-
@Controller:
就是将bean注册到ioc容器中的效果,但是@Controller稍微特殊一点,可以让容器知道他是一个Controller层的类 -
@RequestMapping:
- 标注在方法上,是告诉SpringMVC,这个方法用于处理什么请求,/是可以省略的,默认也是从当前项目开始寻找,加上比较好
-
标注在类上,等于为WEB应用设置了一个根目录,下边的所有资源访问都要带上这一级目录名称例如标注在类上为"/haha",那么访问这个通过这个类下的所有方法访问资源都要带上/haha,访问hello就是/haha/hello以此类推
标注在类上
测试结果
可见效果正是给该类下的资源添加了根路径信息
-
@RequestMapping的其他属性;
method:限定请求方式
method
params:设置请求参数信息,支持简单的表达式
params = {"username"} //请求必须带有名为username的参数
params = {"!username"} //请求不能带有名为username的参数
params = {"username=123"} //请求必须带有名为username的参数且参数值必须为123
params = {"username!=123"} //请求若带有名为username的参数,则参数值不能为123
//注意此时不带username等于值为null,也满足条件
params = {"username","pwd!=123","id=123"} //请求必须满足以上所有规则
headers:设置请求头信息,支持简单的表达式
consumes:规定请求头中Content-type信息
produces:告诉浏览器响应的类型是什么,等于给响应头加上Content-type信息
-
@RequestMapping的模糊匹配功能
?:能替代任意一个字符
?
访问成功
*:能替代任意夺个字符和一层路径
*替代字符 访问成功 *替代路径 访问成功
**:能替代多层路径
** 访问成功
注意:当满足多个匹配条件时,精确度高的匹配优先度更高(明确 > ? > * > **),例如有haha和h?h?,但是指定资源不同,访问haha会访问haha指定的精确资源而不会访问模糊匹配的资源
-
路径中可以有占位符,效果就是占据一层路径,可以是任意字符,搭配@PathVariable注解可以获取路径中占位符处的值
获取值
REST风格的URL
REST:(资源)表现层状态转化
springMVC支持REST风格的URL
传统的url区分CRUD操作:
获取:/getInfo?id=1
更新:/updateInfo?id=1
删除:/deleteInfo?id=1
添加:/addInfo
当操作多了,取名会很多,很复杂
而rest的思想就是,URL统一为/资源名/资源表示符,转而使用不同的提交方式来区分CRUD操作
rest风格url区分CRUD:
获取:/Info?id=1 使用GET方式提交
更新:/Info?id=1 使用PUT方式提交
删除:/Info?id=1 使用DELETE方式提交
添加:/Info 使用POST方式提交
问题:从页面只能发出get和post两种请求,怎么办?
测试:使用rest风格的url完成CRUD实验
环境搭建:
在controller类中根据四种不同的请求方式,给页面传递不同的信息,模拟CRUD操作
@Controller
public class myController {
@RequestMapping(value = "/info/{sid}",method = RequestMethod.GET)
public String getInfo(@PathVariable("sid")Integer id, Model model) {
model.addAttribute("msg","成功获取了"+id+"号学生的信息");
return "success";
}
@RequestMapping(value = "/info",method = RequestMethod.POST)
public String addInfo(Model model) {
model.addAttribute("msg","成功添加了新的学生的信息");
return "success";
}
@RequestMapping(value = "/info/{sid}",method = RequestMethod.DELETE)
public String deleteInfo(@PathVariable("sid")Integer id, Model model) {
model.addAttribute("msg","成功删除了"+id+"号学生的信息");
return "success";
}
@RequestMapping(value = "/info/{sid}",method = RequestMethod.PUT)
public String updateInfo(@PathVariable("sid")Integer id, Model model) {
model.addAttribute("msg","成功更新了"+id+"号学生的信息");
return "success";
}
}
页面运行结果
简单测试后发现,因为页面无法发出除了get和post之外的请求,所以点击获取学生信息和增加学生信息可以正常跳转,但是点击更新和删除学生信息默认是以get方式发送请求,所以跳转的依然是获取学生信息的页面
解决方案:
在web.xml中,配置HiddenHttpMethodFilter过滤器
HiddenHttpMethodFilter
在index.jsp页面中,将删除、更新两个超链接更换为post提交方式的表单,并且在表单内添加name属性为"_method",value值为对应提交方式的input标签
页面
之后提交这两个表单就会以name属性为"_method"的input标签的value值规定的方式进行提交
注意:如果使用Tomcat8.0+版本进行测试,会报错,应为Tomcat8之后的版本默认不允许PUT、DELETE等提交方式
错误信息
解决方法:在跳转之后的jsp页面上,将isErrorPage值设置为true
isErrorPage
这之后就可以正常执行了
原理:
观察HiddenHttpMethodFilter过滤器的原码可以发现
原理
请求处理
-
获取请求参数的值
默认方式获取参数值:
直接在方法形参中添加和参数值名称类型相同的属性即可获取
页面
- 当username形参已经在方法中大量使用,此时将请求参数名称改为user,则需要大量的修改,此时可以使用@RequestParam("user")注解来修改获取的参数名称
@RequestParam
此时使用user可以传递参数
测试结果
但是@RequestParam指定的请求参数,默认是必须要有的,即设置之后,请求不能不带这个参数,可以为空,但不能没有,没有就报错
错误
可以通过设置@RequestParam的属性来解决这个问题
required:是否可以为null,true表示不能为null,false表示可以
设置
测试结果
defaultValue:设置默认值,即传空的数据,会默认使用这个数据
注意,设置默认值之后,即使不设置required属性,也可以为null,为null时,也是用默认值
测试结果
-
获取请求头的信息
使用方法与@RequestParam一致
@RequestParam
若请求参数中没有指定的请求头信息,就会报错,此时也可以通过设置属性来解决问题,属性required和defaultValue使用方法效果与@RequestParam一致
-
获取cookie信息
使用@CookieValue可以根据key值获取cookie中对应的值
@CookieValue
若cookie中没有指定的key信息,则报错,此时也可以通过设置属性来解决问题,属性required和defaultValue使用方法效果与@RequestParam一致
-
自动封装pojo类以及级联封装
springmvc强大的功能,可以直接根据参数名自动封装到对应的pojo类中
创建表单
表单
根据表单创建实体类
实体类
修改方法,设置对应实体类的形参
修改方法
测试
测试结果
问题:
1、如果有比实体类更多的请求参数
例如111,则springmvc只会将和实体类set方法名称相同的参数封装到实体类中
2、级联属性封装需要使用级联属性.属性的方式设置请求参数名
3、tomcat8之后,默认解决了get获取中文的乱码问题,而8之前的版本需要将tomcat的server.xml种8080端口后加上编码格式才能不乱吗
4、使用post请求方式会出现乱码问题
问题
解决方式:在web.xml中配置CharacterEncodingFilter过滤器,解决乱码
CharacterEncodingFilter
CharacterEncodingFilter必须配置在所有过滤器之前,应为要在获取请求的第一时间先解决乱码问题
测试结果
6、如果是delete、put等请求方式,解决方案和post一致,因为本质上他们都是post请求方式
7、springmvc支持直接使用原生API
原生API
传输数据到页面
-
使用Model、ModelMap、Map集合共享数据
代码
共同点:
通过这三种方式共享的数据,都在requestScope域中,且他们都是通过实现了BindingAwareModelMap实现了共享数据的功能,本质上是同一个东西
-
使用@SessionAttributes可以将放在请求域中的数据copy一份到session域中,使用key值直接指定或使用type指定类型,但是有bug,所以想共享数据到session中,建议使用原生api,可控,易删除
原生API使用session
转发&重定向
当视图解析器的前缀和后缀设置好之后,若想去其他路径下的页面,可以使用../跳到上一级页面
上一级页面
也可以使用转发,使用forward:+路径可以跳过视图解析器的拼串环节
或者重定向,传统重定向需要带上虚拟目录路径,而在springmvc中,框架会自动帮我们添上
代码 测试结果
二者的区别是转发只能在服务器内部资源中跳转,而重定向可以跳转到其他服务器的资源
且转发可以共享数据,而重定向不行
网友评论