1.SpringMVC框架解决的问题
从技术角度去思考 任何一个现存的框架都有其存在理由,而这个理由就是解决实际的问题。或者提供更好的解决问题的方案。spring mvc 它解决了什么问题呢?
1. URL映射
2. 表单参数映射(不管get还是post请求)
3. 调用目标Controller
4. 数据模型映射(视图和模型之间映射)
5. 视图解析
6. 异常处理
上述解决在spring mvc 中都体现在如下组件当中:
HandlerMapping : 帮助我们找到对应的目标Controller( url与控制器的映射)
HandlerAdapte : 控制器执行适配器(找到数据模型的映射)
ViewResolver : 视图仓库
view : 具体解析视图
HandlerExceptionResolver : 异常捕捕捉器
HandlerInterceptor : 拦截器
2.SpringMVC核心流程解析
web端发起request请求(携带参数),到达dispatchServlet ,dispatchServlet会转发到对应的Controller,Controller对请求进行处理,然后返回一个ModelAndView , 然后dispatchServlet 会找到对应的页面处理器,把这个Model传递给View,然后View进行视图的解析(封装一个Html字符串返回给Response).
3.框架流程解析(SpringMVC)
1.Tomcat启动 开始加载web.xml
Servlet就会创建(配置了load)
然后启动容器
3. 浏览器发送请求,经过前端控制器(DispatcherServlet),截取出来URL路径,
然后找到对应的控制器方法(从@RequestMapping找)然后执行method.invoke方法然后执行method.invoke方法)
然后通过方法的 return 的视图名,
找视图解析器,通过加预先设定好的前缀和后缀去找页面
然jsp会响应给浏览器
4.乱码问题
具体的看 getpost乱码看第一天笔记
post乱码问题:
在web.xml中加入:
.
.
.
.
.
.
.
.
.
.
.
.
以上可以解决post请求乱码问题。
get乱码
对于get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:
.
另外一种方法对参数进行重新编码:
. String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),”utf-8”)
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
5.请求转发和重定向区别
请求转发:【forward:】开头的字符串,后面跟转发的URL路径,URL如果有后缀(.action)要加上。
重定向:【redirect:】开头的字符串,后面跟重定向的URL路径,URL如果有后缀(.action)要加上。
注意:关键字后面的冒号是半角。
请求转发是后台程序方法之间跳转时使用的,由于是后台之间的跳转,因此浏览器中URL不发生改变,这也说明还是在同一个Request请求中,因此转发后的方法仍然可以接收转发前从浏览器提交上来的Request对象的HTTP参数。
重定向相当于再次从浏览器发起一个新的Request请求,由于是从前台重新发起的,因此浏览器中的URL发生改变。由于不是同一个Request请求,因此重定向后的方法不能接收重定向前从浏览器提交上来的HTTP参数。
/**
删除用户信息
*/
@RequestMapping(“/deleteByid”)
public String deleteByid(int id) throws Exception {
**int **flag = **this**.**crudService**.deleteByid(id);
**return "redirect:list"**; //这是重定向
}
重定向不能携带参数,怎么解决问题,可以用model来解决这个问题,
为什么重定向可以使用Model传递参数?
因为重定向的字符串返回时,SpringMVC看到是redirect开头最终由视图解析器解析后会生成一个专门处理重定向的视图View对象:org.springframework.web.servlet.view.RedirectView,这个View会把前端控制器给它的Model数据放到新Request对象的Parameter(HTTP参数)中,这样重定向后就会得到参数了。
如果是非重定向的字符串返回(逻辑视图名或请求转发)时,视图解析器会生成普通的视图View对象:org.springframework.web.servlet.view.InternalResourceView,这个View会把前端控制器给它的Model数据放到同一个Request对象的Attribute(属性)中。
因此大家在使用SpringMVC时要善用Model(ModelAndView)。
Controller方法的返回jsp页面是请求转发还是重定向?
Jsp本身就是一个Servlet对象,Controller方法在向jsp页面跳转后URL并没有发生改变,仍然是提交给方法时候的URL,而且放置在Model(ModelAndView)参数中的数据会被SpringMVC放置到Request对象中,也都在Jsp页面通过EL表达式得到了,这说明它们是一个Request对象,EL表达式通过属性名从Request对象的Attribute中取得了结果值。
因此跳转到JSP页面是请求转发而不是重定向。
Request对象的Parameter和Attribute
Request域指的是Attribute, 我们model底层把数据放到request域里面的attribute里面(相当于调用setAttribute方法放进去了,前台jsp通过EL表达式从域里取值(从attribute里面)).
Request对象的Parameter是指从请求发起端提交上来的参数,出于安全的考虑,这些参数在我们的后台java程序中是无法篡改的。因此只有request.getParameter(“参数名”)方法,但没有setParamete()方法。
Request对象的Attribute是指后台方法与方法对象与对象之间请求转发时,传递数据的,这个可以在后台方法中随便进行set/getAttribute()。
因此,不要混淆这两个集合的用途和概念。
6.SpringMVC与Struts2的主要区别?
①springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
②springmvc是基于方法开发,传递参数是通过方法形参,可以设计为单例或多例(建议单例), struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
③Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,
springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成ModelAndView对象,最后又将模型数据通过request对象传输到页面。 Jsp视图解析器默认使用jstl。
7.MVC模式的优点与不足
MVC模式早在上个世纪70年代就诞生了,直到今天它依然存在,可见生命力相当之强。MVC模式最早用于Smalltalk语言中,最后在其它许多开发语言中都得到了很好的应用,例如,Java中的Struts、Spring MVC等框架。正是因为这些MVC框架的出现,才让MVC模式真正落地,让开发更加高效,让代码耦合度尽量减小,让应用程序各部分的职责更加清晰。
既然MVC模式这么好,难道它就没有不足的地方吗?我认为MVC至少有以下三点不足:
1. 每次请求必须经过“控制器->模型->视图”这个流程,用户才能看到最终的展现的界面,这个过程似乎有些复杂。
2. 实际上视图是依赖于模型的,换句话说,如果没有模型,视图也无法呈现出最终的效果。
3. 渲染视图的过程是在服务端来完成的,最终呈现给浏览器的是带有模型的视图页面,性能无法得到很好的优化。
为了使数据展现过程更加直接,并且提供更好的用户体验,我们有必要对MVC模式进行改进。不妨这样来尝试,首先从浏览器发送AJAX请求,然后服务端接受该请求并返回JSON数据返回给浏览器,最后在浏览器中进行界面渲染。
改进后的MVC模式如图2所示。
也就是说,我们输入的是AJAX请求,输出的是JSON数据,市面上有这样的技术来实现这个功能吗?答案是REST。
REST全称是Representational State Transfer(表述性状态转移),它是Roy Fielding博士在2000年写的一篇关于软件架构风格的论文,此文一出,威震四方!国内外许多知名互联网公司纷纷开始采用这种轻量级的Web服务,大家习惯将其称为RESTful Web Services,或简称REST服务。]
如果将浏览器这一端视为前端,而服务器那一端视为后端的话,可以将以上改进后的MVC模式简化为以下前后端分离模式,如图3所示。
可见,有了REST服务,前端关注界面展现,后端关注业务逻辑,分工明确,职责清晰。那么,如何使用REST服务将应用程序进行前后端分离呢?我们接下来继续探讨,首先我们需要认识REST。
8.SpringMVC为何能准确的找到http请求controller的某个方法来处理
我们需要给一个类加注解@Controller,然后定义一个加了注解@RequestMapping的方法,这样Spring容器就可以准确找到对应的方法了.
在Spring MVC里,有一专门处理请求映射的接口HandlerMapping,查看此接口的实现类:
其中,RequestMappingHandlerMapping是我们需要关注的。我们首先看一下RequestMappingHandlerMapping的抽象父类AbstractHandlerMethodMapping,省略其他方法,先关注这两个相关核心方法
可以看到AbstractHandlerMethodMapping实现了InitializingBean接口,在Spring初始化bean的时候,如果bean实现了InitializingBean接口,会自动调用afterPropertiesSet方法。initHandlerMethods方法,顾名思义是初始化HandlerMethods,查看它是被afterPropertiesSet方法调用,这个方法代表bean在容器中被初始化的时候,会去执行initHandlerMethods方法。
那initHandlerMethods方法具体做了什么事情?大概看一下方法内部的业务,首先拿到容器里的所有bean名称放进数组beanNames中;然后遍历数组,拿到每一个bean的类型beanType,对每一个beanType做了一个判断isHandler(beanType),查看此方法的实现,即进入RequestMappingHandlerMapping中:
·很容易看出来,是去判断该类是否加了注解@Controller或@RequestMapping。点进去查看AnnotatedElementUtils.hasAnnotation方法的实现
所以我们判断一个类上是否加了什么注解,可以这么写:
判断完类上加了注解@Controller或者@RequestMapping后,看到继续执行了detectHandlerMethods方法:
这个方法筛选出了类中加了注解@RequestMapping的方法,放进Map集合methods中,紧接着去遍历每一个method,进入registerHandlerMethod方法,注册到映射注册表mappingRegistry中,其中就是一些Map。
至此,我们就明白了在Spring初始化bean的时候,就把所有的加了@Controller/@RequestMapping的类里面的加了@RequestMapping的方法放进了map中,当http请求来临时,直接去map中迅速拿到对应信息。
SpringMVC的使用
注意,必须要扫描注解和 把Controller层交给Spring容器管理
(二)建立请求URL和控制器之间关系
1.开启SpringMVC对注解支持(在xml里面配置)
### 2.@RequestMapping注解 @RequestMapping注解的主要用途是将Web请求与请求处理类中的方法进行映射。Spring MVC和Spring WebFlux都通过RquestMappingHandlerMapping和RequestMappingHndlerAdapter两个类来提供对@RequestMapping注解的支持,使用@RequestMapping注解之前,还需要给这个注解的类添加@Controller注解.
@RequestMapping(value=””,method={“”,””},headers={},params={“”,””})
作用
用来定义访问的url。可以是方法级别的,也可以是类级别的。两者可以协同工作,缩小选择范围。也可以隐藏代码的真实路径,更加具有安全性和可读性。RequestMapping囊括了更多可配置的参数,不仅仅有提交表单的方式,而且有方法级别响应url请求的地址等信息,更加灵活。
建立请求URL和控制器方法之间的对应关系
@RequestMapping设置的value或者是path就是key
方法就是value ,通过key找value
注意key不能重复,因为重复就不知道找哪个方法
属性:
1.value:指定映射的内容。(它应该和请求url中的保持一致)。除了value,使用path属性也 可以
值的写法:
在控制器中path(value)属性的取值:写不写/都可以。
2.method:设置访问方式,常用的method=RequestMethod.POST,和method=RequestMethod.GET
3.headers:头域,可以设置浏览器支持的格式,根据HTTP Header的存在、缺省或值对请求进行过滤
4. params:访问参数设置,params:根据HTTP参数的存在、缺省或值对请求进行过滤
5. consume:设定在HTTP请求正文中允许使用的媒体类型
意味着请求的HTTP 头的Content-Type 媒体类型与consumes 的值匹配, 才能调用此方法,例如 application/json, text/html;
列子: @GetMapp 工ng(value = ” / consumes/test . json ”, consumes = ” application/json”)
这里映射指定请求的媒体类型是application/ison , 因此,此方法接受一个AJAX 请求。如
果通过浏览器直接访问, 则会看到Spring Boot 报出如下错误,因为通过浏览器访问,通常并没
有设置Content-Type ,所以说null 不支持。
There was an unexpected error (type=Unsupported Media Type , status=415) .
Content type ’ nul l ’ not supported
为了成功调用上述Controller方法,ajax调用必须设置Content -Type 为appli catio n/j s on
6.product:在HTTP响应体中允许使用的媒体类型,produces 指定返回值类型,不但可以设置返回值类型还可以设定返回值的字符编码
1. 比如指定返回json数据,但是可以省略,因为有@ResponseBody
2. 返回json数据的字符编码为utf-8
@RequestMapping(value = “/pets/{petId}”, produces=”MediaType.APPLICATION_JSON_VALUE;charset=utf-8”)
### 3.解决跨域问题@CrossOrigin @CrossOrigin 注解在controller上面写
@RestController @RequestMapping(“api/emergency/emergencyevents”) @CrossOrigin/表示当前控制器支持跨域访问/ public class EmergencyEventsController {
详细参考:
https://www.cnblogs.com/mmzs/p/9167743.html
### 4.配置视图解析器和对注解的支持 视图解析器如果不涉及到页面跳转其实就没有什么意义,比如用ajax异步操作,就不涉及到页面跳转
<bean id=”viewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”>
<property name=”prefix” value=”/WEB-INF/jsp/“/>
<property name=”suffix” value=”.jsp”/>
</bean>
<**mvc:annotation-driven**/>
5.对实体类日期的转换
@DateTimeFormat
页面将数据传到后台,是以字符串的形式。所以时间格式会出错。加上此注解,后台可解析时间格式的字符串。
如果仅仅是日期类型的转化可以不用自定义转换器,还有一种更简单的做法:直接在pojo对应的日期属性变量上面加注解 @DateTimeFormat(pattern=”yyyy-MM-dd HH:mm:ss”)
@DateTimeFormat(pattern = “yyyy:MM:dd HH:mm:ss”)
private Date departureTime;
@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”)
在实体类的Date类型的参数上添加这个注解
总结:
1.如果前后端传的数据都是json格式,那么后台接数据,传数据都可以用@JsonFormat ;
2.@DateTimeFormat适合后端接收前端传来的数据,不管是不是json格式都可以正确转换成Date型数据,只要前端传来的格式正确且后端@DateTimeFormat的pattern写正确。但是,这个注解无法将Date型数据用json传到前端去
6.controller
SpringMVC的controller默认就是单例的
如果你bean配置多例了,依赖这个bean的bean也需要多例才行啊(看例子)
在单例的bean中切记声明成员属性(如Map、List集合来缓存数据),是线程不安全的
7.对静态资源放行处理
在SpringMVC.xml里面配置
说明:location元素:表示webapp目录下(即服务器根目录)的js包下的所有文件;mapping元素:表示以/js开头的所有请求路径,如/js/a 或者/js/a/b;
该配置的作用是:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源交由Servlet处理;
8.能访问jsp却无法访问html
<mvc:default-servlet-handler />
原理:
如果将DispatcherServlet请求映射配置为”/“,则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求,Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。
如何让Spring框架能够捕获所有URL的请求,同时又将静态资源的请求转由Web容器处理,是可将DispatcherServlet的请求映射配置为”/“的前提。由于REST是Spring3.0最重要的功能之一,所以Spring团队很看重静态资源处理这项任务,给出了堪称经典的两种解决方案。
先调整web.xml中的DispatcherServlet的配置,使其可以捕获所有的请求:
<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:spring-mvc.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>
通过上面url-pattern的配置,所有URL请求都将被Spring MVC的DispatcherServlet截获.
方法1.采用
在springMVC-servlet.xml中配置
一般Web应用服务器默认的Servlet名称是”default”,因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是”default”,则需要通过default-servlet-name属性显示指定:
方法2.采用
首先,
其次,
在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
在springMVC-servlet中添加如下配置:
以上配置将Web根路径”/“及类路径下 /META-INF/publicResources/ 的目录映射为/resources路径。假设Web根路径下拥有images、js这两个资源目录,在images下面有bg.gif图片,在js下面有test.js文件,则可以通过 /resources/images/bg.gif 和 /resources/js/test.js 访问这二个静态资源。
假设WebRoot还拥有images/bg1.gif 及 js/test1.js,则也可以在网页中通过 /resources/images/bg1.gif 及 /resources/js/test1.js 进行引用。
9.通过ip端口映射本地的文件夹路径
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class UploadFilePathConfig extends WebMvcConfigurerAdapter {
/*配置浏览器通过url访问本地文件夹下的图片等等,
以下配置的是本地文件夹地址是"e://JavaExploit/"
程序员可以通过访问 http://localhost:9999/file/6baf3b6f.jpg 在浏览器上显示图片<br /> * */<br /> @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(**"/file/**"**).addResourceLocations(**"file:" **+ **"e://JavaExploit/"**);
(三)@ResponseBody对json的处理
使用:需要导入依赖,依赖在使用的下面
java代码
@ResponseBody
@RequestMapping(“/hvxm”)
public Lmxi hvxm() {
Lmxi lmxi = **this**.**accountService**.hvxm(2);
System.out.println(**"lmxi = " **+ lmxi);
**return **lmxi;
}
控制台
前台打印是
//*
需要导入依赖(2.7.0以下的用不了):
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>s
@ResponseBody作用
ResponseBody 注解直接将返回的对象输出到客户端,如果是字符串, 则直接返回: 如果不是,则默认使用Jackson 序列化成JSON 字符串后输出。
作用:作用于方法上,将方法返回的对象,通过HttpMessageConverter接口转换成指定格式的数据: 比如json和xml等等,通过Response想应给客户端(说白了就是将方法返回的数据转成json响应给客户端)
1.修改序列化解析器为fastjson
| <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> | | —- |
| package com.fancy.projecty.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.ArrayList;
import java.util.List;
//将一个物理类变成一个配置文件
@Configuration
//适配器
public class WebMvcConfig extends WebMvcConfigurerAdapter {
/**
* 利用fastjson替换掉jackson,且解决中文乱码问题<br />
* **@param ****_converters<br />
_***/<br />
@Override
public void configureMessageConverters(List
//1.构建了一个HttpMessageConverter FastJson 消息转换器
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
//2.定义一个配置,设置编码方式,和格式化的形式
FastJsonConfig fastJsonConfig = new FastJsonConfig();
//3.设置成了PrettyFormat格式
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
//4.处理中文乱码问题
List
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
//5.将fastJsonConfig加到消息转换器中
fastConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastConverter);
}
} |
| —- |
(四)文件上传
需要引入坐标依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
jsp页面
注意:
method=”post” enctype=”multipart/form-data” 不能改变 请求也不能改变
name=”uploadFile” 不能改变,因为SpringMVC内部会用这个东西
java代码
/**
- 开始文件上传
形参:MultipartFile uploadFile 都不要改变
*/
@RequestMapping(“/fileUpload”)
public String fileUpload(HttpServletRequest request, MultipartFile uploadFile) throws Exception {
//获取上传路径
String basePath = request.getSession().getServletContext().getRealPath(**"/uploads"**);
//防止每个文件目录过多.设置二级目录
String datePath = **new **SimpleDateFormat(**"yyyy-MM-dd"**).format(**new **Date());
//判断两个目录是否存在
File file = **new **File(basePath, datePath);
**if **(!file.exists()) {
file.mkdirs();<br /> }<br /> //获取文件名
String originalFilename = uploadFile.getOriginalFilename();
//为了防止文件重名,随机化文件名
String uuid = UUID.randomUUID().toString().replace(**"-"**, **""**).toUpperCase();
originalFilename = uuid + **"_" **+ originalFilename;
//写文件
uploadFile.transferTo(**new **File(file, originalFilename));
**return "success"**;<br />
}
还需要在SpringMVC.xml里面配置文件上传解析器
<bean id=”multipartResolver” class=”org.springframework.web.multipart.commons.CommonsMultipartResolver”>
<property name=”maxUploadSize”>
<value>5242880</value>
</property>
</bean>
SpringMVC核心
要想引入SpringMVC做表现层开发,最基本的需要完成两件事:
1. 配置前端控制器。
2. 开发后端控制器。
(五)控制器和解析器
前端控制器
前端控制器(DispatcherServlet): org.springframework.web.servlet.DispatcherServlet,它是SpringMVC接收web请求的第一入口,也是唯一入口。这是一个servlet对象,因此需要在web.xml中进行配置。
DispatcherServlet启动后会立刻去找SpringMVC的配置文件,然后根据配置文件中的内容进行加载和扫描
还需要配置加载SpringMVC配置文件
后端控制器
用@Controller注解将一个java类声明为SpringMVC后端控制器
注意!!! 需要配置扫描包
@RequestMapping 定义后端控制器的方法
视图解析器
异常解析器
具体看day95 07视频 08视频自定义异常
(六)获取页面参数三种方法
jsp页面,点击submi提交请求到后台,后台需要获取页面“用户名”与“密码”输入框中的值
1.传统的 request.getParameter(“uname”);//同Servlet一样,获取页面属性名叫uname的值
2. 注解机制@RequestParam(“uname”)String username——获取页面属性名叫”uname”的值,用String类型接收,变量名叫username
3.JavaBean自动装配机制 创建一个实体类,实体类的属性需要和前台控件name属性值一致
(七)模型对象(Model和ModelAndView)
Model和ModelAndView 可以给页面赋值
模型对象,是SpringMVC默认支持的一种形参类型,由SpringMVC自动创建,使用时只需定义在方法形参上即可。
作用:可以向Model参数中添加页面需要的变量(属性名)和结果值(属性值),SpringMVC会负责将Model中的变量赋值给request对象,这样JSP就可以用EL表达式从request对象中取得这个变量(属性名)的数据了。(赋值__request对象就是调用了request.setAttribute(属性名, 属性值)方法完成的。)
ModelAndView形参类似Model,但额外提供了一个视图名称
注意:Model不能在方法中自己构造,因为Model本身是一个接口,所以只能由SpringMVC帮助实例化
(八)参数绑定
基本参数绑定
Springmvc作为表现层框架,是后端程序的入口,它负责接收页面HTTP请求(POST/GET)过来的参数,参数可以是【url后面拼接的】,也可以是【页面控件的值】,也可以是【hidden变量的值】,也可以是【ajax提交的js对象】,也可以是【ajax提交的json字符串】等等。这也体现了本课开始时说的SpringMVC的第一个作用:“接收请求中的参数”。
1. 默认支持的参数类型:HttpServletRequest,HttpServletResponse,HttpSession,
Model(ModelAndView)
2. Java简单类型:int,long,double,String,Long,Double,Boolean,Integer等
3. POJO类型
4. POJO的包装类型-QueryVo
简单的传参规范,页面控件提交的name属性必须等于controller方法的形参名.(适合单个和少数的参数的请求)
pojo类型页面提交的控件name属性值必须等于Controller方法形参对象中的属性名。(适合多参数、不固定参数个数的请求。)
QueryVo页面提交控件的name属性值必须等于Controller方法形参对象中的属性.属性.属性….。(适合综合查询条件参数的传递。)
高级参数绑定
数组类型的参数可以传递一批相同的数据到Controller的方法中。
应用场景:批量删除
功能分解: 前端 能选中多个商品,能提交选中的多个商品
后端 能接收选中商品的id; 进行删除处理
提交相同名称的参数时候,SpringMVC会把它们处理成数组
传参规范:页面提交的控件name属性值必须等于Controller方法数组形参名或者形参对象中的数组属性名。
方式: 1.直接在形参里面传递数组参数
2.在VO里面传递数组参数
List集合类型
可以利用list集合类型的参数传递多条数据进行批量处理,比如批量更新
应用场景:实现商品数据的批量修改
需求分析:要想实现商品数据的批量修改,需要在商品列表中可以对商品信息进行 修改,并且可以批量提交修改后的商品数据。提交的数据应该是一个 List。
功能分解:
前端:1)列表改成input输入框;2)定义改好的input框的name属性;
后端:1)能接收到提交过来的更新数据;2)批量更新处理
<%@ page language=“java” contentType=“text/html; charset=UTF-8”
pageEncoding=“UTF-8”%>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core“ prefix=“c” %>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt“ prefix=“fmt”%>
<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd">
附:
varStatus属性常用参数总结下:
${status.index} 输出行号,从0开始。
${status.count} 输出行号,从1开始。
${status.current} 当前这次迭代的(集合中的)项
${status.first} 判断当前项是否为集合中的第一项,返回值为true或false
${status.last} 判断当前项是否为集合中的最后一项,返回值为true或false
begin属性、end属性、step属性分别表示:起始序号,结束序号,跳跃步伐。
其中[]被encode了,仔细辨认可以看出来。
提交名称开头相同,又带有下标和后缀名的参数,SpringMVC会根据形参中的List属性的定义,按照这个List属性中泛型的类型进行参数绑定。
1. 传参规范SpringMVC不能直接传递List集合类型的参数,必须包装在java bean中。这是SpringMVC框架的强制要求。
2. 页面上input框的name属性值必须等于Controller方法形参java bean中List属性名 + [集合下标] + . + List泛型中的属性名
(九)SpringMVC注解们
1.@Controller(是Spring的东西,SpringMVC也需要.)
注解作用:注册Bean到Spring上下文,Bean的默认ID为类名称首字母小写,也可以自己指定。
2.@value注解
用来获取当前容器中key对应的值(注意是当前容器,在别的容器就取不到)
比如:引入properties文件里面的内容时候使用的 括号里面用EL表达式来取值
3.@RequestParam(required=,value=””,defaultValue=””)
如果Controller方法形参不符合传参规范,可以使用@RequestParam注解进一步限定请求参数到方法形参的映射关系。
属性:
value属性对应着前台控件name属性,用来解决name属性和形参名字不一致问题
required:boolean类型,声明此请求参数是否必须有,true的时候如果没有,则报错。
defaultValue:字符类型,如果请求参数没有提供,可以指定一个默认字符串,Spring会自动将字符串转化为形参的目标类型(当然这种类型转化必须是简单类型转化)。
说白了就是给形参赋值
4.@CookieValue(了解)
作用:用于指定cookie的名称的值传给控制器方法参数
属性:
value:指定cookie名字
required:是否必须有此cookie
5.@SessionAttributes(用处不大,还不如用request自带的session了)
默认情况下Spring MVC将模型中的数据存储到request域中。当一个请求结束后,数据就失效了。如果要跨页面使用。那么需要使用到session。而@SessionAttributes注解就可以使得模型中的数据存储一份到session域中
作用:用于实现多次请求的数据共享。(就是把数据存入Session域中)
属性:
names:这是一个字符串数组。里面应写需要存储到session中数据的名称。
value:用于指定存入session域中的key
types:用于指定存入session域中的数据类型
@SessionAttributes(value= {“username”,”password”},types=Integer.class)
它只能声明类上。
@Controller @SessionAttributes(value={“names”},types={Integer.class}) public class ScopeService { @RequestMapping(“/testSession”) public String test(Map map.put(“names”, Arrays.asList(“a”,”b”,”c”)); map.put(“age”, 12); return “hello”; } } |
---|
6.获取请求头 @RequestHeader
@ApiOperation(value = “退出登录功能”) @GetMapping(“/logout”) public SuccessVO logout(@Autowired CustomRealm customRealm, @RequestHeader String token) { System.err.println(token); |
---|
7.@ModelAttribute(没有,使用效率太低)
写在方法上意思是在别的控制器执行之前先执行被这个注解标注的方法,返回值可以共享到别的方法(返回值的东西加到map里面.这个map是ModelMap ,也是Model)
写在参数名上就是指定在map中哪个key给这个对象赋值