SpringMVC
创建Maven包
初始化Maven添加相应依赖包
<packaging>war</packaging>
<dependencies>
<!--springMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!--日志-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.0-alpha16</version>
</dependency>
<!--ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--Spring5和tymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
创建webapp,新建文件夹webapp,设置web工程

更改相应路径

再次回到webapp的目录,出现蓝点且存在WEB-INF/web.xml则配置成功
配置web.xml
默认配置方式
<!--配置SpringMVC的前端控制器,对浏览器的请求统一处理-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatchServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
扩展配置方式
<!--配置SpringMVC的前端控制器,对浏览器的请求统一处理-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置位置和名称-->
<init-param>
<param-nam· e>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!--将前端控制器DispatchServlet的初始化时间提前到服务器启动时-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

创建请求控制器

@Controller
public class HelloController {
}
扫描组件

视图解析器
<!--视图解析器-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"></property>
<property name="characterEncoding" value="UTF-8"></property>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!--视图前缀 -->
<property name="prefix" value="/WEB-INF/templates"/>
<!--视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
404错误由tomcat版本所致
更换tomcat9下的版本
@RequestMapping
value属性
编写在类上面,相当于根目录
编写在方法上,表示具体的路径
@Controller @RequestMapping("/demo") public class testController { @RequestMapping("/test1") public String test(){ return "test"; } @RequestMapping("test2") public String test2(){ return "test2"; } }访问路径:test1: /demo/test1 test2:/demo/test2
value值可以为数组 value={“/demo1”,“demo2”},表示可通过两个路径访问
value属性必须设置值
method属性
method=RequestMethod.GET
method=RequestMethod.POST
params属性:表示请求信息中对请求参数的限制
params={“username”,“age!=10”}:表示请求参数中必须带有username,且age!=10
Ant匹配风格:
- ?:匹配文件名中的一个字符
- *:匹配文件名中的任意字符
- **:匹配多层路径(/ /中间放符号)
@PathVariable():可以将URL请求路径中的参数传递到处理请求方法的形参中
处理请求数据
@RequestParam注解:可以把请求参数传递给请求方法
value:参数名
required:是否必须,默认为true
defaultValue:默认值,没有传递参数时使用的值
@RequestHeader注解(value,required,defaultvalue):绑定请求报头的属性值,服务区可通过此注解获取报头的属性值
@CookieValue注解(value,required,defaultvalue):绑定请求中的Cookie值
创建cookie:通过调用
public String testServletAPI(HttpServletRequest request){ HttpSession session=request.getSession(); }
POJO作为参数
springMVC会按请求参数名和POJO属性名进行自动匹配,自动为该对象填充属性值
配置字符编码过滤器
web.xml配置
<filter>
<filter-name>encodingFilter</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>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
域对象共享数据
使用servletAPI向request域对象共享数据
<a th:href="@{/testScope}">测试servletAPI获取数据域</a> @Controller public class testScope { @RequestMapping("/testScope") public String testScope(HttpServletRequest request){ request.setAttribute("testScope","Hello Rush!"); return "testScope"; } }使用ModelAndView向request域对象共享数据
@RequestMapping("/testScopeByMAV") public ModelAndView testMAV(){ ModelAndView mav=new ModelAndView(); mav.addObject("testScope","Test ModelAndView"); mav.setViewName("testScope"); return mav; }通过Model向request域对象共享数据
通过Map向request域对象共享数据
map.put(key,value);
ModelMap
ModelMap.addAttribute();
通过servletAPI向session域对象共享数据
HttpSession session;
session.setAttribute();
通过servletAPI向application域对象共享数据
同6
Map、Model、ModelMap之间的关系
使用的都是同执行类
public interface Model{} public class ModelMap extends LinkedHashMap<String,object>{} public class ExtendedModelMap extends ModelMap implements Model{} public class BindingAwareModelMap extends ExtendedModelMap{}
SpringMVC的视图
- ThymeleafView
- InternalResolveView
RESTful实现增删改查
开启mvc视图解析,无需通过@RequestMapping,需添加注解驱动,否则ThymeleafViewResolver将失效(resource下的xml配置文件)
<mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/addUser" view-name="addUser"/> <mvc:annotation-driven/>创建静态资源文件vue.js(可从官网下载相关文件)

创建实体类,静态创建用户数据,并编写相应增删改查的代码(entity与dao包)

@Repository public class UserDao { private static Map<Integer, User> user=null; static { user=new HashMap<Integer,User>(); user.put(1001,new User(1001,"张三","aaa@qq.com",1)); user.put(1002,new User(1002,"张师弟","bba@qq.com",0)); user.put(1003,new User(1003,"张wu","aaa@qq.com",0)); user.put(1004,new User(1004,"张流","aaa@qq.com",1)); user.put(1005,new User(1005,"张三","aaa@qq.com",1)); } //增删改查 private static Integer index=1006; public void saveUser(User user1){ if(user1.getId()==null){ user1.setId(index++); } user.put(user1.getId(),user1); } public Collection<User> getAll(){ return user.values(); } public User getByID(Integer id){ return user.get(id); } public void delete(Integer id){ user.remove(id); } }控制器编写相应路径代码
@Controller public class RestTController { @Autowired private UserDao userDao; @RequestMapping(value = "/user",method = RequestMethod.GET) public String getAll(Model model){ Collection<User> userLst =userDao.getAll(); model.addAttribute("userList",userLst); return "user"; } @RequestMapping(value = "user/{id}",method = RequestMethod.GET) public String getById(@PathVariable(value = "id") Integer id,Model model){ User user=userDao.getByID(id); model.addAttribute("user", user); return "updateUser"; } @RequestMapping(value = "user/{id}",method = RequestMethod.DELETE) public String delete(@PathVariable(value = "id")Integer id){ userDao.delete(id); return "redirect:/user"; } @RequestMapping(value = "/user",method = RequestMethod.POST) public String addUser(User user){ userDao.saveUser(user); return "redirect:/user"; } @RequestMapping(value = "/user",method = RequestMethod.PUT) public String updateUser(User user){ userDao.saveUser(user); return "redirect:/user"; } }index.html作为首页入口

user.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>user info</title> </head> <body> <table id="dataTable" border="1" cellspacing="0" cellpadding="0" style="text-align: center"> <tr> <th colspan="5">User Information</th> </tr> <tr> <th>id</th> <th>name</th> <th>email</th> <th>gender</th> <th>options(<a th:href="@{/addUser}">添加</a> )</th> </tr> <tr th:each="user:${userList}"> <td th:text="${user.id}"></td> <td th:text="${user.name}"></td> <td th:text="${user.email}"></td> <td th:text="${user.gender}"></td> <td> <a @click="deleteUser" th:href="@{'/user/'+${user.id}}">delete</a> <a th:href="@{'/user/'+${user.id}}">update</a> </td> </tr> </table> <form id="deleteForm" method="post"> <input type="hidden" name="_method" value="delete"> </form> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript"> var vue=new Vue({ el:"#dataTable", methods:{ deleteUser:function (event) { console.log("点击了") var deleteForm=document.getElementById("deleteForm"); deleteForm.action=event.target.href; deleteForm.submit(); event.preventDefault(); } } }) </script> </body> </html>开放对静态资源的访问
<!--开放对静态资源的访问 --> <mvc:default-servlet-handler/>注意重新加载包

addUser.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>user info</title> </head> <body> <table id="dataTable" border="1" cellspacing="0" cellpadding="0" style="text-align: center"> <tr> <th colspan="5">User Information</th> </tr> <tr> <th>id</th> <th>name</th> <th>email</th> <th>gender</th> <th>options(<a th:href="@{/addUser}">添加</a> )</th> </tr> <tr th:each="user:${userList}"> <td th:text="${user.id}"></td> <td th:text="${user.name}"></td> <td th:text="${user.email}"></td> <td th:text="${user.gender}"></td> <td> <a @click="deleteUser" th:href="@{'/user/'+${user.id}}">delete</a> <a th:href="@{'/user/'+${user.id}}">update</a> </td> </tr> </table> <form id="deleteForm" method="post"> <input type="hidden" name="_method" value="delete"> </form> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript"> var vue=new Vue({ el:"#dataTable", methods:{ deleteUser:function (event) { console.log("点击了") var deleteForm=document.getElementById("deleteForm"); deleteForm.action=event.target.href; deleteForm.submit(); event.preventDefault(); } } }) </script> </body> </html>注意Vue.js的语法:方法区的定义为methods,不是method,否则将报错使用的方法未定义
updateUser.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>updateUser</title> </head> <body> <form th:action="@{/user}" method="post"> <input type="hidden" name="_method" value="put"> <input type="hidden" name="id" th:value="${user.id}"> name:<input type="text" name="name" th:value="${user.name}"><br> email:<input type="text" name="email" th:value="${user.email}"><br> gender:<input type="radio" name="gender" value="1" th:field="${user.gender}">male <input type="radio" name="gender" value="0" th:field="${user.gender}">female<br> <input type="submit" value="update"><br> </form> </body> </html>
HttpMessageConvert报文信息转换器
提供了两个注解和两个类型@RequestBody、@ResponseBody、RequestEntity、ResponseEntity
- @ResponseBody将内容或对象作为Http响应正文(返回json格式)
- @RequestBody将Http请求正文插入方法中,修饰目标方法的入参
<!--Json包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
@Controller
public class ResponseEntityController {
@RequestMapping("/testResponse")
@ResponseBody//自动转换为json对象
public User testResponseUser(){
return new User(1008,"RUSH","rush@xf.com",1);
}
}

处理Ajax
引入js包

<div id="app">
<a @click="testAjax" th:href="@{/testAjax}">处理Ajax</a>
</div>
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
new Vue({
el:"#app",
methods:{
testAjax:function (event) {
console.log("点击了")
axios({
method:"post",
url:event.target.href,
params:{
username:"rush",
password:"123456"
}
}).then(function (response) {
console.log("axios生效了")
alert(response.data);
});
event.preventDefault();
}
}
})
</script>
@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username,String password){
System.out.println("username:"+username+" password:"+password);
return "hello world";
}
@RestController注解
@RestController是SpringMVC中的一个复合注解,标识在控制器的一个类上,就相当于在类上添加@Controller注解,在方法上添加@ResponseBody注解
ResponseEntity
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
文件上产和下载
使用ResponseEntity实现下载文件的功能
@Controller public class FileUploaderController { @RequestMapping("/testDown") public ResponseEntity<byte[]> testResponseEntity(HttpSession session)throws IOException{ //获取ServletContext对象 ServletContext servletContext=session.getServletContext(); //获取服务器中文件的真实路径 String realPath=servletContext.getRealPath("/static/video/testVideo.mp4"); //创建输入流 InputStream is=new FileInputStream(realPath); //创建字节数组 byte[] bytes=new byte[is.available()]; //将流读到字节数组中 is.read(bytes); //创建HttpHeaders对象设置响应头信息 MultiValueMap<String,String> headers=new HttpHeaders(); //设置要下载方式以及下载文件的名字 headers.add("Content-Disposition","attachment;filename=testVideo.mp4"); //设置响应状态码 HttpStatus statusCode=HttpStatus.OK; //创建ResponseEntity对象 ResponseEntity<byte[]> responseEntity=new ResponseEntity<>(bytes,headers,statusCode); //关闭输入流 is.close(); return responseEntity; } }文件上传功能
上传表单
<form th:action="@{/testUpload}" method="post" enctype="multipart/form-data"> <input type="file" name="image"><br> <input type="submit" value="上传文件"> </form>配置依赖包
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>配置文件上传解析器
<!--配置文件上传解析器,将上传的文件封装为MultipartFile--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>编写程序
@RequestMapping("/testUpload") public String testUpload(MultipartFile image,HttpSession session) throws IOException { String fileName= image.getOriginalFilename(); ServletContext servletContext=session.getServletContext(); String imagePath= servletContext.getRealPath("image"); File file=new File(imagePath); if(!file.exists()){ file.mkdir(); } String finalPath=imagePath+File.separator+fileName; image.transferTo(new File(finalPath)); return "success"; }解决文件名重名问题:将文件的后缀切分出来与随机字符拼接即可(UUID)
//获取文件名后缀 String suffixName=fileName.substring(fileName.lastIndexOf(".")); //将UUID作为文件名 String uuid= UUID.randomUUID().toString().replaceAll("-",""); fileName=uuid+suffixName;
拦截器
拦截器的配置
SpringMVC中的拦截器用于拦截拦截控制器的方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor或继承HandlerInterceptorAdapter类并重写方法
@Controller public class FirstInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("FirstInterceptor-->preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("FirstInterceptor-->postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("FirstInterceptor-->afterCompletion"); } }SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置
<mvc:interceptors> <!--拦截所有--> <!-- <bean class="com.xf.mvc.interceptor.FirstInterceptor"></bean>--> <!-- <ref bean="firstInterceptor"></ref>--> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/"/> <ref bean="firstInterceptor"></ref> </mvc:interceptor> </mvc:interceptors>
异常处理器
基于配置的异常处理器:SpringMVC提供了一个处理控制器方法执行过程中出现的异常的接口:HandlerExceptionResolver,HandlerExceptionResolver接口的实现类有DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
<!--配置异常处理--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!--properties的键表示处理器方法执行过程中出现的异常 properties的值表示出现异常所跳转到异常的视图名称--> <prop key="ArithmeticException">error</prop> </props> </property> <!--exceptionAttribute属性设置属性名,将出现的异常信息在请求域中进行共享--> <property name="exceptionAttribute" value="error"></property> </bean>基于注解的异常配置
@ControllerAdvice public class ExceptionController { @ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class}) public String testException(Exception ex, Model model){ model.addAttribute("ex",ex); return "error"; } }基于注解配置的SpringMVC
使用配置类和注解代替web.xml和SpringMVC配置文件的功能
创建初始类、代替web.xml
在Servlet(某版本)中,容器会在路径中查找实现javax.servlet.ServletContainerInitlallizer接口的类,如果找到的话就用它来配置这个servlet容器
Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成,Spring3.2引入了一个WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatchServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatchServletInitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer { /** * 指定spring的配置类 * @return */ @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } /** * 指定SpringMVC的配置类 * @return */ @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{WebConfig.class}; } /** * 指定DispatchServlet的映射规则 * @return */ @Override protected String[] getServletMappings() { return new String[]{"/"}; } /** * 注册过滤器 * @return */ @Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter=new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); characterEncodingFilter.setForceResponseEncoding(true); HiddenHttpMethodFilter hiddenHttpMethodFilter=new HiddenHttpMethodFilter(); return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter}; } }对SpringMVC进行配置
/** * 代替SpringMVC的配置文件 * 1、扫描组件 2、视图解析器 3、view-controller 4、default-servlet-handler * 5、MVC注解驱动 6、文件上传解析器 7、异常处理 8、拦截器 */ @Configuration @ComponentScan("com.xf.mvc") //开启MVC注解驱动 @EnableWebMvc public class WebConfig implements WebMvcConfigurer { //default-servlet-handler @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } //拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { TestInterceptor testInterceptor= new TestInterceptor(); registry.addInterceptor(testInterceptor).addPathPatterns("/**"); } //view-controller @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/hello").setViewName("hello"); } //文件上传解析器 @Bean public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver(); return commonsMultipartResolver; } //异常处理 @Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { SimpleMappingExceptionResolver exceptionResolver=new SimpleMappingExceptionResolver(); Properties prop=new Properties(); prop.setProperty("java.lang.ArithmeticException","error"); exceptionResolver.setExceptionMappings(prop); exceptionResolver.setExceptionAttribute("exception"); resolvers.add(exceptionResolver); } //配置生成模板解析器 @Bean public ITemplateResolver templateResolver(){ WebApplicationContext webApplicationContext= ContextLoader.getCurrentWebApplicationContext(); ServletContextTemplateResolver templateResolver=new ServletContextTemplateResolver(webApplicationContext.getServletContext()); templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setSuffix(".html"); templateResolver.setCharacterEncoding("UTF-8"); templateResolver.setTemplateMode(TemplateMode.HTML); return templateResolver; } //生成模板引擎并为模板引擎注入模板解析器 @Bean public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver){ SpringTemplateEngine templateEngine=new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; } //生成视图解析器并为解析器注入模板引擎 public ViewResolver viewResolver(SpringTemplateEngine templateEngine){ ThymeleafViewResolver viewResolver=new ThymeleafViewResolver(); viewResolver.setCharacterEncoding("UTF-8"); viewResolver.setTemplateEngine(templateEngine); return viewResolver; } }
lateResolver.setCharacterEncoding(“UTF-8”);
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}