SpringMVC
SpringMVC的执行流程
简要分析执行流程
-
DispatcherServlet表示前端控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
http://localhost:8080服务器域名
SpringMVC部署在服务器上的web站点
hello表示控制器
通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
-
HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。(在还没有用注解开发时,最开始会在xml中配置handler)
<!--Handler--> <bean id="/hello" class="com.ccunix.controller.HelloCoontroller"/> -
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
-
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
-
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
-
Handler让具体的Controller执行。
-
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
-
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
-
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
-
视图解析器将解析的逻辑视图名传给DispatcherServlet。
-
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
-
最终视图呈现给用户。


配置SpringMVC的步骤
第一种方式
1、在web.xml中配置前端控制器
<!--前端控制器-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springMVC的配置文件-->
<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>
<!--
/与/*的区别
/不会拦截.jsp文件
/*会拦截.jsp文件和url路径
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
2、springmvc-servlet.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--添加 处理映射器--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--添加 处理器适配器--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!--视图解析器:DispatcherServlet给他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> <!--Handler--> <bean id="/xxx" class="xx.xx.xx.controller.xx"/> </beans>
第二种方式
1、在web.xml中配置前端控制器,与第一种方式的一样
2、springmvc-servlet.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" 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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--开启扫描 因为springmvc是负责controller层的 所以只扫描controller就好了--> <context:component-scan base-package="xx.xx.controller"/> <!--前端控制器,哪些静态资源不拦截 比如.css .js--> <mvc:default-servlet-handler/> <!--开启springMVC框架注解的支持--> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <mvc:annotation-driven/> <!--视图解析器:DispatcherServlet给他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> <!--配置文件解析器 要求id值必须为multipartResolver--> <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"> <!--10*1024*1024 10M--> <property value="10485760" name="maxUploadSize"/> </bean> <!--拦截器--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/admin/**"/> <bean class="org.ccunix.coffee.interceptor.AdminLoginInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>
RestFul风格
这个是传统的url地址
http://localhost:8080/index/user/add?a=1&b=2
@Controller @RequestMapping("/user") public class RestFulController { @RequestMapping("/add") public String add( Integer a, Integer b, Model model){ int result = a + b; model.addAttribute("msg","结果为"+result); System.out.println(result); return "add"; } }
restful风格的url
http://localhost:8080/user/mult/1/2
@RequestMapping(value = "/mult/{a}/{b}",method = RequestMethod.GET)
public String mult( @PathVariable("a") Integer a, @PathVariable("b") Integer b, Model model){
int result = a + b;
model.addAttribute("msg","结果为"+result);
System.out.println(result);
return "add";
}
@RequestMapping(value = "/mult/{a}/{b}",method = RequestMethod.GET)相当于是Get方法的restFul请求
可以简写@GetMapping("/mult/{a}/{b}")
restFul接口请求分类
get、post、put、delete、patch
同理这些请求提交方式也都有相应的注解
SpringMVC中我们可以直接return "页面名",然后根据视图解析器进行拼接成为要访问的页面。
在没有配置视图解析器时,就要自己配置访问的路径return "/WEB-INFO/jsp/xx" 但是地址栏的url并没有改变,所以这个操作就是转发,也可以写为return "forward: /WEB-INFO/jsp/xx"。
在配置了视图解析器时,这个return "页面名" 相当于 return "forword : 页面名",当然也可以用重定向 return "redirect: 页面名" 但是它不会走视图解析器,而且还不能访问WEB-INFO下的页面。
为什么redirect重定向不能访问WEB-INF目录下的内容?
WEB-INF是Java的WEB应用的安全目录。所谓安全就是客户端无法访问,只有服务端可以访问的目录。
页面放在WEB-INF目录下面,这样可以限制访问,提高安全性.如JSP,html。
原因
既然WEB-INF是安全目录,客户端无法访问,而重定向就相当于用户直接从客户端访问了的路径,自然就不可以啦,只有程序内部转发的时候才能转发到WEB-INF下的JSP。
拦截器
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
-
servlet规范中的一部分,任何java web工程都可以使用
-
在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
-
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
-
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
自定义拦截器
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
package org.ccunix.coffee.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class AdminLoginInterceptor implements HandlerInterceptor { /** * controller方法执行前 先执行, 如果该方法返回false 则controller方法不会执行 * * 登录成功后需要在Session中存储adminLoginUser的内容存储用户信息 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); //没有进行通过 if(session.getAttribute("adminLoginUser")==null){ System.out.println("先进行登录验证"); response.sendRedirect(request.getContextPath()+"/toAdminLogin"); return false; }else { //验证通过 return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
文件上传
1、在springmvc配置文件中要配置bean
【注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!】
2、前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的 enctype 属性做个详细的说明:
-
application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
-
multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
-
text/plain:除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
CommonsMultipartFile 的 常用方法:
-
String getOriginalFilename():获取上传文件的原名
-
InputStream getInputStream():获取文件流
-
void transferTo(File dest):将上传文件保存到一个目录文件中
//上传路径保存
String realPath = request.getSession().getServletContext().getRealPath("/images/before"); System.out.println(realPath);
//判断路径 File file = new File(realPath); if(!file.exists()){ file.mkdirs();//创建一个 } //确定文件名称 String uuid = UUID.randomUUID().toString().replace("-",""); //获得原来的名字 String fileName = photo.getOriginalFilename(); //截取拿到文件的后缀名 int dianIndex = fileName.lastIndexOf("."); //对后缀名进行判断 不是图片格式的不能上传 fileName = uuid+fileName.substring(dianIndex); //将文件名保存到coffeePOJO coffeePOJO.setPicture("images/before/"+fileName); //写出上传文件到指定文件中 photo.transferTo(new File(file,fileName));
遇到的问题
(1)构建web项目中webapp没有小蓝点,需要在project structure中设置。



在这里将webapp的路径,正确的填入。

这时就成为了完整的web项目。
(2)启动项目时Tomcat报错
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/catalina/loader/WebappClassLoader) previously initiated loading for a different type with name "javax/servlet/ServletContext"
这是因为在pom.xml文件中导入servlet坐标时没有设置好作用域

这样就好了,成功解决问题。

浙公网安备 33010602011771号