springmvc的hello world
1、导包(自行导包)
2、配置web.xml文件
<pre>
springmvc基于servlet,配置的第一步是在WEB-INF/web.xml中配置servlet。
</pre>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>springmvc</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!--
1:配置核心控制器servlet
2:再配置servlet的映射地址
-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
load-on-startup可以指定Servlet被创建的时机,而且这里的数字越小,初始化就越靠前,
通常写1,会在当前的应用被初始化加载到tomcat之后立马进行实例化
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
1:通配符:只能有两种固定的格式:
一种格式是"*.扩展名"。另一种格式是以正斜杠(/)开头并以"/*"结尾
注意:既带/又带扩展名的不合法。
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3、springmvc.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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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-4.3.xsd">
<!-- 采用注解方式实现,扫描带有@Controller的注解 -->
<context:component-scan base-package="com.bjlemon.controller"></context:component-scan>
<!-- 静态资源映射。当<url-pattern>/</url-pattern>时,该配置必须出现 -->
<mvc:resources mapping="/script/**" location="/script/"></mvc:resources>
<mvc:resources mapping="/style/**" location="/style/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
<!-- 开启注解驱动:会自动采用系统默认的handlerMapping和handlerAdapter进行处理我们的请求 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver
">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
4、写一个HelloController类
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello() {
System.out.println("hello world");
ModelAndView model=new ModelAndView();
model.setViewName("hello");
model.addObject("msg", "hello springmvc");
return model;
}
}
5、编写一个hello.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${msg}
</body>
</html>
6、测试
配置好后,就可以通过浏览器访问(根路径取决于项目配置)
http://127.0.0.1/springmvc/hello
如果访问成功,控制台后打印 hello world,jsp页面也会显示hello springmvc
springmvc的执行流程
- 第一步:发起请求到前端控制器(DispatcherServlet)
- 第二步:前端控制器请求处理器映射器(HandlerMapping)查找 Handler(可以根据xml配置、注解进行查找)
- 第三步:处理器映射器(HandlerMapping)向前端控制器返回Handler
- 第四步:前端控制器调用处理器适配器去执行Handler
- 第五步:处理器适配器去执行Handler
- 第六步:Handler执行完成给处理器适配器返回ModelAndView
- 第七步:处理器适配器向前端控制器返回ModelAndView(ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
- 第八步:前端控制器请求视图解析器去进行视图解析(根据逻辑视图名解析成真正的视图(jsp))
- 第九步:视图解析器向前端控制器返回View
- 第十步:前端控制器进行视图渲染(将模型数据(在ModelAndView对象中)填充到request域)
- 第十一步:前端控制器向用户响应结果
重要的五个组件
> 前端控制器(DispatcherServlet)
> 处理器映射器(HandlerMapper)
> 处理器适配器(HandlerAdapter)
> 处理器(Handler)
> 视图解析器(ViewResolver)
springmvc常用的注解
- RequestMapping:映射请求地址,可用于类或方法上
- PathVariable:获取占位符中的参数
- RequestParam:用于设置请求参数,有三个参数
- value:参数名
- required:是否必须
- defaultValue:默认参数值。如果设置了该参数会自动将required设置为false
- ResponseBody:这个类的所有方法返回的数据直接写给浏览器(如果是对象转为json数据)
- RequestBody:将请求的json字符串转化为pojo对象
springmvc与struts2的比较
- springmvc的入口是servlet,而struts的入口是filter
- springmvc是方法级别的拦截,一个方法对应一个request上下文,而一个方法同时又与一个url对应,所以从架构本身上springmvc更容易实现restful url,而struts2是类级别的拦截,不容易实现restful url,因为struts2中Action的一个方法可以对应一个url,但其类属性却被所有方法共享,无法用注解或其他方式标识其所属方法了
- 由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
- SpringMVC开发效率和性能高于Struts2。
- Spring MVC和Spring是无缝集成
重定向(redirect)
model.setViewName("redirect:/user.jsp");
转发(forward)
model.setViewName("forward:/hello");
springmvc文件上传
- 导入需要依赖的jar包
org.apache.commons.fileupload
org.apache.commons.io
- 配置文件上传解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 单个文件的大小2M 2*1024*1024 -->
<property name="maxUploadSizePerFile" value="2097152"></property>
<!-- 文件的总大小为10M 10*1024*1024 -->
<property name="maxUploadSize" value="10485760"></property>
</bean>
- 搭建一个用于文件上传的页面
<form action="${pageContext.request.contextPath}/upload/upload" method="post" enctype="multipart/form-data">
文件:<input type="file" name="file"><br>
<input type="submit" value="上传">
</form>
- 写一个测试方法用于接收单个文件上传
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest request, Model model){
try {
ServletContext context=request.getSession().getServletContext();
String path=context.getRealPath("/images");
File uploadDirectory=new File(path);
if(!uploadDirectory.exists()){
uploadDirectory.mkdirs();
}
String filename=file.getOriginalFilename();
file.transferTo(new File(uploadDirectory,filename));
model.addAttribute("fileName",filename);
return "upload/result";
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
拦截器
自定义拦截器实现HandlerInterceptor接口,该接口定义了3个方法,需要我们实现
> preHandle在handler执行之前被触发的方法
> postHandle在handler执行之后被触发的方法
> afterCompletion在视图渲染完之后被触发的方法
- 自定义拦截器
public class InterceptorTest1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("InterceptorTest1 preHandle");
System.out.println(handler);
//如果返回true表示将请求传给下一个拦截器
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("InterceptorTest1 postHandle");
System.out.println(handler);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("InterceptorTest1 afterCompletion");
System.out.println(handler);
}
}
- 在springmvc.xml中配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置要拦截所有的路径 -->
<mvc:mapping path="/**"/>
<!-- 配置拦截器 -->
<bean class="com.bjlemon.web.interceptor.InterceptorTest1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.bjlemon.web.interceptor.InterceptorTest2"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--排除某个路径-->
<!--<mvc:exclude-mapping path="/user/login"></mvc:exclude-mapping>-->
<bean class="com.bjlemon.web.interceptor.InterceptorTest3"></bean>
</mvc:interceptor>
</mvc:interceptors>
类型转换
- 自定义一个类实现Converter接口
//自定义类型转换器,第一个参数是指输入的参数类型,第二个参数是指输出的参数类型
public class StringToDateConverter implements Converter<String, Date> {
public static final String[]DEFAULT_PATTERNS=new String[]{"yyyy-MM-dd"};
private String[]patterns=DEFAULT_PATTERNS;
public void setPatterns(String[] patterns) {
this.patterns = patterns;
}
@Override
public Date convert(String s) {
Date date=null;
if(StringUtils.isBlank(s)){
throw new IllegalArgumentException("");
}
try {
date= DateUtils.parseDate(s,this.patterns);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
}
- 在springmvc.xml配置文件中注册添加该转换器
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.bjlemon.web.converter.StringToDateConverter">
<property name="patterns">
<array>
<value>yyyy-MM-dd</value>
<value>yyyy/MM/dd</value>
<value>yyyy-MM-dd HH:mm:ss</value>
</array>
</property>
</bean>
</set>
</property>
</bean>
异常的处理
- 自定义异常类
public class MyException extends RuntimeException {
private String message;
public MyException(String message) {
super(message);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- 自定义异常处理器,实现HandlerExceptionResolver接口
public class MyExceptionHandlerResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView=new ModelAndView();
String message="程序出错了,请联系管理员";
if(ex!=null){
if(ex instanceof UnknownAccountException){
UnknownAccountException unknownAccountException=(UnknownAccountException)ex;
message=unknownAccountException.getMessage();
}else if(ex instanceof IncorrectCredentialsException){
IncorrectCredentialsException incorrectCredentialsException=(IncorrectCredentialsException)ex;
message=incorrectCredentialsException.getMessage();
}else if(ex instanceof UnauthorizedException){
modelAndView.setViewName("redirect:/index/unauthorized");
return modelAndView;
}else if(ex instanceof MyException){
MyException myException=(MyException)ex;
message=myException.getMessage();
}
}
modelAndView.addObject("errorMessage",message);
modelAndView.setViewName("common/error");
return modelAndView;
}
}
- 在springmvc.xml配置文件中配置定义好的异常解析器
<bean id="myExceptionHandlerResolver" class="com.bjlemon.exception.MyExceptionHandlerResolver"></bean>
请求参数乱码问题
<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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>