spring MVC 应用
一 :spring MVC 介绍
1:spring mvc 是啥?
spring mvc 是spring框架功能的一部分
负责controller处理器,基于MVC设计模式
底层实现了封装了servlet,简化web开发
2: spring mvc 框架的作用
springMVC :web端的框架
- 简化获取请求参数
- 简化作出相应
spring:ioc|di
1.对象的创建和管理,只负责用对象,不负责生产对象
2.aop 简化代码,横向的散落到核心业务中
3. jdbc 数据库工具类,简化jdbc操作,适合多表查询
4. test,不需要每次都自己搭建测试环境 5. tx:简化业务层事物的添加,
3:spring mvc 框架的容器组成
常规的web项目开发需要两个容器,
一个是springMVC 的ioc 容器,内部装了controller和其他相关的view 相关的
内容springmvc 可以调用spring容器。而且是单向的,
另一个是spring的容器ioc的容器,内部封装了service repository etc 可以被
springmvc调用,但是他不能调用springmvc里面的内容
4:springmvc框架的核心组件
- dispatcherServlet:本质是一个servlet,而且是项目中唯一的servlet,他是所用请求的入口和出口
在web.xml 里面配置一下
handlerMapping:处理器映射器,内部记录对应的地址的映射
handlerAdapter:避免sipatcherservlet直接调用handler(controller)简化请求参数,相应处理
handler:就是以后的controller,开发人员要处理请求的地方,处理请求是以方法为单位,更加简单的获取请求参数,调用业务逻辑,更加简单的作出相应
viewResolver:视图解析器,将你返回的字符串找到对应的页面,返回给dispatcher,最后回给前面页面
二: springMVC 框架的基本使用
步骤一:导入jar依赖
spring core…
spring-web: 整合整个web项目的
spring-webmvc springmvc框架的包
步骤二:创建controller(handler)
步骤三:编写配置文件
springmvcioc 容器相关,(controller handleradapter,handlermapping viewResolver)
<!--handler自己定义的controller--> <!--handlerMapping handleradapter viewresovler 框架已经定义好了我们只需要ioc --> <!--handler--> <context:component-scan base-package="com.it.controller"></context:component-scan> <!--handlermapping--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> <!--handlerAdapter--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean> <!--jsp--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/"></property> <!--后缀--> <property name="suffix" value=".jsp"></property> </bean>
web.xml : dispatcherservlet初始化容器
<!--dipatcherServlet--> <servlet> <servlet-name>ds</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--初始参数--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicatonContext.xml</param-value> </init-param> <!--提前初始化--> <load-on-startup>1</load-on-startup> </servlet> <!--映射--> <servlet-mapping> <servlet-name>ds</servlet-name> <!--拦截所有除了jsp--> <url-pattern>/</url-pattern> </servlet-mapping>
步骤四:访问测试
三:spring MVC 框架的常用的注解
@RequestMapping
- 位置:可以添加在方法 类(接口)上面
- 作用:将当前controller添加到handlerMapping中
- 参数:value String [] 具体映射路径,
注意方法上必须添加,类上面可以不添加。默认方法的路径
- 且属性是个数组 String value[] ({“path1”,“path2”…})
- 也可以 path String [] = {“path1”,“path2”…}但是得申明path={}的形式
- method RequestMethod[] 允许的请求方式:post get
> method={RequestMethod.POST,RequestMethod.GET}
@RequestParam(“name”)
简化参数部分
- 原始方案获取参数
在handler对应的方法中传入请求和响应对应的对象(resquest,response)
再使用请求对象获取参数
缺点:没有用到springmvc的优点
在handler对应的方法的参数列表中声明对应参数的名称和对应形参的类型
优点:更加方便的获取到了参数
缺点: 1.形参名必须要 和传参的名字相同
2. 方法中有太多的形参不是一件好事
如果参数名和形参名不同,可以在形参类型前面加上,一旦指定形参名字,就不会再找到形参的名称了
@RequestParam(“name”)
@RequestParam的属性:
1. name
如果参数过多,都写入形参列表可不是一件漂亮事,因此,把这些参数都封装成一个对象,我们只需要把对象传入里面就可以,适配子会帮我们解析参数。
前端三要素:
- method=post
- encytype = multipart/from=data
3. input type=file后端解析:
1. commons-io
- conmmons-fileipload
原始文件上传步骤:&&&&&&&&&&&&&&&&
- 创建磁盘解析工厂
2. 创建核心解析器- 传入磁盘解析器
4. 循环判断,传入的文件是字符还字节- 文件类型进行存储到本地磁盘
mvc方式:
- 方法中形参(MultipartFile file)
MutipartFile涉及的方法
1. getName()返回input里面输入的nam属性 2. getOriginalName()原始文件名 3. getSize()文件大小 4. transferTo(new File("d/myfile")存储到磁盘位置
- 在mvc配置文件中进行解析器申明(fileupload)
文件解析器是给handleradapter配置的
但是handler是根据解析器的命名进行DI的
在ioc中要求命名固定
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8" /> <property name="maxUploadSize" value="#{20*1024*1024}" /> </bean>
5.@PathVariable
截取路径中的参数
为了获取路径动态传入的参数
获取路径动态传参
方法(@PathVariable 参数类型 参数名)
默认:参数名取的http 请求的传参,而不会取到路径中的动态路径部分
注意:
@PathVariable如果形参名he动态路径名一致,{名称}不需要额外的执行
如果不一致@PathVariable(name=“动态路径名”) 形参
@PathVariable(name=“pid”) 和 @RequestParam(name=“pid”)
相同点:ElementType.PARAMETER
不通电:PathVariable获取动态路径中{pid}
RequestParam获取请求参数中叫pid ?pid=xx6.@CookieValue
位置:方法内参
作用:快速获取cookie的value并赋值给形参
属性:name:cookie的名称 value:cookie的值 defaultValue 默认值
例如:@CookieValue(value=“JSESSIONID”,defalutValue=“xxx”)String jsessionid
7. RequestHeader
位置:方法内参
作用:获取请求头的信息赋给方法的形参
属性:name value defulatValue请求头不存在的时候,默认值
四:springMVC 框架简化响应部分
响应方式:
springmvc 框架提供了视图解析器,可以配合视图解析求得前缀后缀,在handler的方法中,返回页面的名字面积可以找到对应的页面。返回类型是一个字符串!
注意:
- 前提字符串前面不能加特殊’转发和重定向符号’! 字符串前不能包含 forward: redirect:
2.不能使用restcontroller responsebody注解如何将数据放到共享域!
servletContext
httpsession 重定向 一会会话
request 转发!
pageContext方案一:传统方法
handler方法上可以传入请求对象!
请求对象获取其他的共享域!set/get/removeAttribute();
方案2: spring简化存储共享域的方式
modelAndView: 数据和视图:
自己将数据放到modelandview对象!同时把要跳转的视图路径!将modelandview对象返回!springmvc视图解析器会自动识别并转发到对应的页面!同时将modelandview中的数据放到request共享域!
使用
- handler返回值变成ModelAndView
- 方法中创建一个modelandview对象
- modelandview设置视图.setViewName(“index”);
- modelandview添加数据.addobject(key,value);
model:只携带数据!
map:根model是一样的!
1. 返回值的类型必须是String 2. 参数中传递一个map或者model 3. 向map或者model中添加数据即可! 4. adapter会拿到map和model获取数据,放到共享域中!
总结:以上三种提供数据放入共享域的方案! modelandview,model,map默认存在到request共享域!
默认存在到request共享域!handler类上添加 @SessionAttributes(names={“当初你往以上三个对象添加的key”})
forward:/项目下的路径即可! 不用项目的根路径!方法返回值是是字符串
redirect:/项目下的路径即可! 不用项目的根路径!方法返回值是字符串
类:类下的所有方法都返回字符串!方法:单一方法返回字符窜!
@RestController = @Controller+@ResponseBody
- 返回一个对象或者一个集合或者map或者map集合
- 导包 jackson-databind
- 配置json转化器
配置转化器方法1:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" > <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html; charset=UTF-8</value> <value>application/json;charset=UTF-8</value> </list> </property> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html; charset=UTF-8</value> <value>application/json;charset=UTF-8</value> </list> </property> </bean> </list> </property> </bean>
3. 配置转化器方法2:<mvc:annotation-driven />
他替代了handlermapping handleradapter handleradapter的转化器等等!
4. json返回数据处理
实例类处理json生成数据:
@JsonInclude(JsonInclude.Include.NON_NULL) //不为null属性才会生成json
位置:实体类上!
@JsonInclude(JsonInclude.Include.NON_NULL) //不为null属性才会生成json public class User { @JsonProperty("user_name") private String name; @JsonIgnore private int age; private String info; @JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss",timezone = "GMT+8") private Date date;
@RequestMapping("/bt") public void returnBys(HttpServletResponse response) throws IOException { ServletOutputStream outputStream = response.getOutputStream(); }
数据传输问题:
ajax+html返回字符串
jsp(共享域)数据‘传递’
五: springMVC 解决静态资源拦截以及跨域请求问题
- 静态资源处理
动态资源值得不止资源本身,而是资源的执行结果
静态资源处理
方案1:
<mvc:default-servlet-handler />
后期再做handler路径声明的时候,尽量不要起静态资源后缀名的!
方案2: 指定映射文件夹
<mvc:resources mapping="/static/**" location="/static/" />
mapping指定要放行的路径!
location放行的路径对应的文件夹!
**问题:**一旦指定了放行的路径!就不能给handler起对应的路径命名!
建议: 使用第一种!
- 跨域访问问题
同原路径:当一个页面!内部发起一个ajax请求!请求某一个路径获取资源!浏览器会判断,当前访问页面的路径和ajax发起请求访问的路径!是否是同源!
如果同源:浏览器正常帮助发起ajax请求,并得到返回结果!如果非同源: 浏览器拒绝给你返回数据!他认为你在访问他人的项目,而且没得到运行!
除非第三方的服务器运行其他的源访问!浏览器才会给你返回数据!
如何区分同源:
先看协议版本
再看ip地址
最后看端口号 http://127.0.0.1:8080 http://localhost:8080 非同源
https://www.baidu.com http://www.baidu.com 非同源
http://www.baidu.com:80 http://www.baidu.com 同源
http://www.baidu.com:8080/qf http://www.baidu.com:8080/baidu 同源
默认情况下 web项目是运行浏览器根据同源策略进行资源拦截!
服务器如何放弃同源策略!
同源策略需要在springmvc的容器配置中添加!注意不是web.xml
<mvc:cors> <mvc:mapping //当前项目的任何路径 运行外部访问 path="/**" allowed-origins="*" 允许任何其他域名访问 allowed-methods="POST, GET, OPTIONS, DELETE, PUT,PATCH" 允许任何方式访问 allowed-headers="Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With" allow-credentials="true" /> </mvc:cors>
六: springMVC的拦截器
Javaweb中 servlet处理请求 listener监听请求 filter过滤器请求(放行)只拦截servlet,静态资源
HandlerInterceptor拦截器
区别:
handlerinterceptor出现在springmvc内部调用
filter只能在dispatcherservlet之前出现,因此filter拦截更加强硬,handlerInterceptor拦截更加精细化,可以出现在springmvc的一个组件请求和响应位置。
使用
- 如何申明拦截
创建一个类实现HandlerInterceptor接口并实现里面的三个方法
- 拦截那些位置
- boolean perHandler(request,response,Handler)
返回值为false表示要拦截,拦截后要给用户友好提示,所以要用到 重定向或者转发
- void postHandler(request,response,Handler)
handler 执行完毕后在再进行其他验证,例如登陆后的权限验证
- void afterComplettion(request,response,Handler,exceptitor)
该方法在渲染完毕后,就是视图解析器找到页面的时候
- 设置拦截路径
位置:在springmvc配置文件中
- 声明拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="具体拦截路径"/> <!--拦截器位置--> <bean class="com.it.interceptor.MyInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
注意:
1. 拦截路径无需写项目根路径 2. 拦截路径方式: 1. 层次路径 xxx/xxx/xx 2. 通配符拦截 ?(一层单个字符) *(一层多个字符) **(多个层次,多个字符拦截)
- 使用拦截器,验证有没有登录等。
1.完善登录功能 登录页面 登录处理 登录展示 如何判断有没有登录! session 2.拦截功能 1. /user/* /user/xxx /user 拦不拦截呢? 2. /user/** /user/xx /user 拦不拦截呢? 3. /**/user/* /user/a 拦不拦截呢? /user拦不拦截呢
七:springmvc自带异常处理功能
1.利用状态码进行页面跳转
判断对应的状态码给用户一个友好的提示!一般用于404! web.xml <!-- 标注错误码以及对应的路径--> <error-page> <error-code>404</error-code> <location>/static/html/404.html</location> </error-page> 适合使用的场景:4系列 非代码错误!给用户友好提示可以修改的! 一下两种适合.代码异常! 500系列! 1.我网络异常请两个小时后再试 2.改bug 代码异常必须触发某一个方法! 2.handler局部异常处理 作用范围:一个handler @ExceptionHandler public String dealException(RuntimeException re, HttpServletRequest request){ //当当前的handler中的方法出现异常! //只有当前的controller出现异常 //1.发送邮件 System.out.println("发送邮件"); //2.友好提示 return "info"; } 注意:1.不需要添加requestmapping 2.可以添加responsebody! 3.可以转发或者重定向或是视图显示 3.全局异常处理 注意:全局处理可以根据对应的异常类型进行单独处理! @ControllerAdvice public class ExceptionHandler {
//下面的方法要捕捉那个异常! @org.springframework.web.bind.annotation.ExceptionHandler(NullPointerException.class) public String dealException(NullPointerException ex, Model model){ String message = ex.getMessage(); //1.发送邮件 System.out.println("发送邮件");
model.addAttribute("ms", "空指针异常!");
return "info"; } //ArithmeticException @org.springframework.web.bind.annotation.ExceptionHandler(ArithmeticException.class) public String dealException2(ArithmeticException ex, Model model){ String message = ex.getMessage(); //1.发送邮件 System.out.println("发送邮件");
model.addAttribute("ms", "除零异常!");
return "info"; } }
如果有具体和非具体的异常!具体异常优先!
八:springmvc整合spring框架
如果一个项目中使用了spring框架和springmvc框架,这个项目一定有两个配置文件,就是springioc文件和springmvcIOC容器,而且mvcioc容器是ioc容器的子容器。
springmvc容器可以引用spring的容器的bean,
spring不可以获取mvc的bean(ioc di aop tx jdbc)
各自的角色:
mvc是控制器层的(简化响应,简化接收参数)
springservice层和dao 层(service和dao的ioc容器,aop,tx,spring-jdbc)
各自容器的内容:
springmvc: controller handlermapping handleradapter viewresolver interceptor
default-servlet-handler json转化器 mutilpartfileresovler cors
springioc: service dao adviece tx aop
各自的配置文件
ioc容器: ioc容器初始化的时机: web —> ioc初始化的时机: —>web项目启动(web项目部署到运行中的tomcat服务器中!)
具体初始化点:servlet filter listener
servlet—默认第一次访问,申明 load-on-startup
listener–选择对应的listener类型 servletecontextlistener
filter—默认项目启动时初始化
springmvc初始化点:
dispatcherservlet --> init 声明 load-on-startup 1
值为mvc的配置文件
contextConfigLocation classpath:applicationContext-web.xmlspring框架选择的初始化点: spring选择的初始化点事 listener servletcontextlistener
大致思路: 声明一个全局的变量!
contextConfigLocation classpath:applicationContext.xml又声明了spring框架提供的contextloaderlistener(servletcontextlistener)在listener.init()进行全局变量contextConfigLocation,拿到spring配置文件进行spring的容器的初始化!
容器结果:
spring的容器: key:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
springmvc的容器: org.springframework.web.servlet.FrameworkServlet.CONTEXT.servlet-name
九:spring ioc容器和spring MVC容器的关系
试验一:springmvc容器中引用spring容器中的bean
结果:可以引用
实验二:spring中引用springmvc中的bean
Assert():报红;
结果:spring容器无法找到springmvc容器中的bean!
开发中业务是单向调用,除非特殊情况。
controller --> | service – > dao --> jdbcutils --> datasoure
如果service一定要引用controller怎么办?
方案一:在controller和service放到springmvc容器中
结果:夭折spring容器中无法再找到springmvc中的service,因此
aop、tx、无法实现
方案二:在spring容器中引入controller
springmvc只会找到自己容器中的controller,修改springmvc框架中的controller
在handlemapping中:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> <property name="detectHandlerMethodsInAncestorContexts" value="true" /> </bean>
十:总结
1.spring+springmvc整合!
2.理解spring+springmvc容器的初始化过程!
3.spring容器和springmvc容器的关系!
4.springmvc框架的执行流程和核心组件以及作用!
5.springmvc涉及的核心注解Skills:
<!-- use-default-filters = false 下面才生效--> <context:component-scan base-package="com.itqf" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <mvc:annotation-driven /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
ajax获取数据问题
$.ajax({ url:"${pageContext.request.contextPath}/all", //data:"name=张三&money=1100", contentType:"application/json;charset=UTF-8", data: {name:"张三",money:110}, type:"GET", success:function (data) { alert(data) //注意:如果响应的类型是application/json不需要再进行转换! //data jsonstr //JSON.parse(data); } })