SpringMVC是围绕DispatcherServlet设计的
SpringMVC的执行原理
- DispatcherServlet表示前置控制器。是整个SpringMVC的控制中心,用户发送请求,DispatcherServlet接收并拦截请求
- HandlerMapping为处理器映射,DispatcherServlet调用HandlerMa批评,HandlerMapping根据请求的url查找handler
- HandlerExecution表示具体的handler,主要作用是根据根据url查找控制器。
- HandlerExecution将解析后的信息传递给DispatcherServlet
- HandlerAdapter表示处理器适配器,按照特定的规则去执行handler
- handler让具体的controller执行
- controller将具体的执行信息返回给HandlerAdapter(如:Model And View)
- HandlerAdapter将其传递给DispatcherServlet
- DispatcherServlet调用视图解析器View Resolver来对信息进行解析
- DispatcherServlet根据视图解析器的解析结构调用具体的视图
- 将视图呈现给用户
HelloSpring
配置版
导入springMVC依赖
配置web.xml文件,注册DispatcherServlet,所有的请求都经过DispatcherServlet拦截处理
<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> <!--/ 匹配所有的请求;(不包括.jsp)--> <!--/* 匹配所有的请求;(包括.jsp)--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
</servlet>
在springmvc-servlet.xml的配置文件中添加处理器映射器和处理器适配器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
添加视图解析器,解析ModelAndView对象
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean>
编写业务实现Controller接口,返回一个ModelAndView对象,封装数据与视图
public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView=new ModelAndView(); //封装对象,model modelAndView.addObject("msg","HelloSpringMVC"); //封装要跳转的视图名称 modelAndView.setViewName("hello"); return modelAndView; } }
将业务类交给spring管理,编写jsp文件并配置Tomcat服务器即可启动
注解版
修改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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.deng.controller" /> <context:annotation-config/> <mvc:default-servlet-handler/> <mvc:annotation-driven/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver " id="internalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"/> </bean> </beans>
编写Controller
@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/hello") public String sayHello(Model model){ model.addAttribute("msg","hello,SpringMVC"); return "hello"; } }
Controller及RestFul
Controller
由接口定义和注解定义两种方法实现,负责解析用户的请求并将其转换为一个模型
实现Controller接口
Controller接口在org.springframework.web.servlet.mvc包下,接口中只有一个方法
//实现该接口的类获得控制器功能 public interface Controller { //处理请求且返回一个模型与视图对象 ModelAndView handleRequest(HttpServletRequest var1,HttpServletResponse var2) throws Exception; }
实现该方法即可获得控制器功能
ModelAndView mv = new ModelAndView(); //绑定一个数据model mv.addObject("msg","Test1Controller"); //绑定一个视图 mv.setViewName("test");
使用注解@Controller
@Controller用于声明Spring类的实例是一个控制器
Spring可以通过包扫描机制来找到应用程序中所有基于注解的控制器类,只需在配置文件中声明:
<context:component-scan base-package="com.deng.controller"/>
@RequestMapping
@RequestMapping用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上表示类中所有响应请求的方法都是以该地址作为父路径
RestFul风格
RestFul就是一个资源定位和资源操作的风格。
传统的方式操作资源:通过不同的参数来实现不同的效果
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
RestFul操作资源:通过不同的请求方式实现不同的效果,请求地址引用,但是根据不同的请求方式实现的功能不一样
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
使用@RequestMapping的method属性可以指定请求的类型
//映射访问路径,必须是POST请求 @RequestMapping(value = "/hello",method = {RequestMethod.POST}) public String index2(Model model){ model.addAttribute("msg", "hello!"); return "test"; }
所有的地址栏请求默认是Get请求
注解的变体有
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
结果跳转的方式
ModelAndView
设置ModelAndView对象,根据view的名称和视图解析器跳转到指定页面
页面:{视图解析器前缀}+view名称+{视图解析器后缀}
<!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean>
public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //返回一个模型视图对象 ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1"); mv.setViewName("test"); return mv; } }
ServletAPI
通过设置ServletAPI进行输出和跳转,就不需要视图解析器
@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/test1") public void test1(HttpServletRequest request,HttpServletResponse response) throws IOException { response.getWriter().print("Hello,World!"); } //重定向 @RequestMapping("/test2") public void test2(HttpServletRequest request,HttpServletResponse response) throws IOException { response.sendRedirect("/hello/test1"); } //请求转发 @RequestMapping("/test3") public void test3(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("/hello/test1").forward(request,response); } }
SpringMVC
可以通过SpringMVC来实现转发和重定向,也无需视图解析器(配置视图解析器就是指定路径)
@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/test1") public String test1(){ return "/index.jsp"; } //请求转发 @RequestMapping("/test2") public String test2(){ return "forward:/index.jsp"; } //重定向 @RequestMapping("/test3") public String test3(){ return "redirect:/index.jsp"; } }
数据处理
处理提交数据
提交域名参数和处理方法的参数名一致
@RequestMapping("/test1") public String test1(String name){ System.out.println(name); return "/index.jsp"; }
访问:localhost:8080/hello/test1?name=dengwenxiong,后台获取到参数
提交域名参数和处理方法不一致
@RequestMapping("/test1") public String test1(@RequestParam("username") String name){ System.out.println(name); return "/index.jsp"; }
访问:localhost:8080/hello/test1?username=dengwenxiong
提交一个对象
@RequestMapping("/test1") public String test1(User user){ System.out.println(user); return "/index.jsp"; }
访问:localhost:8080/hello/test1?id=1&name=dengwenxiong&age=11
提交对象的话,前端传递的参数名和对象名必须是一致的,否则参数为null
数据显示到前端
通过ModelAndView显示
public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //返回一个模型视图对象 ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1"); mv.setViewName("test"); return mv; } }
通过ModelMap
@RequestMapping("/hello") public String hello(@RequestParam("username") String name, ModelMap model){ //封装要显示到视图中的数据 //相当于req.setAttribute("name",name); model.addAttribute("name",name); System.out.println(name); return "hello"; }
通过Model
@RequestMapping("/ct2/hello") public String hello(@RequestParam("username") String name, Model model){ //封装要显示到视图中的数据 //相当于req.setAttribute("name",name); model.addAttribute("msg",name); System.out.println(name); return "test"; }
对比
- Model只有少量方法适用于存储数据
- Model Map继承了LinkedMap,除了实现自身的一些方法外,还继承了LinkedMap的方法和特性
- ModelAndView可以在存储数据的同时设置返回的逻辑视图。
乱码问题
在web.xml配置过滤器即可,SpringMVC提供了一个默认的过滤器
<filter> <filter-name>encoding</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> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
JSON
JSON:js对象标记
- 对象表现为键值对
- 花括号保存对象
- 方括号保存数组
Json对象转换为JS对象
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
js对象转换为Json对象
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
Controller返回JSON字符串
Jackson是目前较好的json解析工具
输出json字符串
导入jar包
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.4</version> </dependency>
@RequestMapping("/user") public class UserController { @RequestMapping("/json") @ResponseBody public String json1() throws JsonProcessingException { //创建jackson的对象映射器来解析数据 ObjectMapper objectMapper=new ObjectMapper(); User user=new User(1,"dwx",11); //将对象解析成json格式 String string=objectMapper.writeValueAsString(user); //@ResponseBody注解,直接返回字符串 return string; } }
如遇到乱码问题可以通过@RequestMapping的produces属性来设置返回类型和编码格式:
//produces:指定响应体返回类型和编码 @RequestMapping(value = "/json",produces ="application/json;charset=utf-8")
@Controller+@ResponseBody=@RestController
输出时间对象
jackson默认会把时间日期转换为时间戳的形式输出
public String json1() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); //不使用时间戳的方式 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); //自定义日期格式对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //指定日期格式 mapper.setDateFormat(sdf); Date date = new Date(); String str = mapper.writeValueAsString(date); return str; }
FastJson
阿里开发的json转换的jar包
导入
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version> </dependency>
有三个主要的类:
- JSONObject:代表json对象,实现了map接口
- JSONArray:代表json数组,实现了List
- JSON:代表JSONArray和JSONObject的转化
AJAX
Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)是一种在无需加载整个网页的情况下,就能更新部分网页的技术。ajax依赖于XMLHttpRequest对象(XHR)
XMLHttpRequest对象:
- 用于后台与服务器交互数据是一种api
- 可以在不重新加载页面的情况下更新网页
- 可以在页面已加载后重服务器请求和接收数据
- 可以向服务器发送数据
ajax请求的五个步骤:
- 创建XMLHttpRequest对象
- 连接服务器
- 发送请求
- 服务器响应
- 接收响应数据
拦截器
SpringMVC的拦截器类似于Servlet中的过滤器,用于对处理器进行预处理和后处理,拦截器只会拦截控制器方法。
自定义拦截器必须实现HandlerInterceptor方法
public class MyInterceptor implements HandlerInterceptor { //预处理,返回true就继续执行,返回false不往下执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("处理前"); return false; } //后处理 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("处理后"); } //dispatcherServlet处理之后执行,完成一些清理工作 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("清理"); } }
配置文件配置拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*"/> <bean class="com.deng.controller.MyInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
可以使用拦截器实现登录拦截
文件上传,下载
SpringMVC可以很好的支持文件上传,但是其上下文默认没装配MultipartResolver,因此默认情况下不能处理文件上传工作。需要在上下文配置MultipartResolver才能使用文件上传功能
对于前端,要上传文件需要将表单的method设置为post,将enctype设置为multipart/form-data,才能将文件以二进制数据发送给服务器
表单中的enctype属性值:
- application/x-www=form-urlencoded:默认的方式,只6处理表单域中的value属性,并会把该属性处理成url编码方式
- multipart/form-data:这种编码方式会以二进制流的形式处理表单数据,会把文件域指定的文件的内容也封装到请求参数中,不会对字符编码
- text/plain:除了把空格转换成+外,其他字符都不做处理,适合通过表单发送邮件
<form action="" enctype="multipart/form-data" method="post"> <input type="file" name="file"/> <input type="submit"> </form>
CommonsFileUpload实现了一个MulitipartResolver的实现类CommonsMultipartResolver。
CommonsMultipartFile常用方法:
- String getOriginalFilename():获取上传文件名
- InputStream getInputStream():获取上传文件输入流
- void transferTo(File file):将上传的文件保存到一个目录文件中
导入文件上传jar包commons-fileupload
<!--文件上传--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <!--servlet-api导入高版本的--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency>
配置multipartResolver的bean
<!--文件上传配置--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="utf-8"></property> <property name="maxUploadSize" value="10485760"></property> <property name="maxInMemorySize" value="40960"></property> </bean>
前端
<form action="/upload" enctype="multipart/form-data" method="post"> <input type="file" name="file"/> <input type="submit" value="upload"> </form>
Controller类
@Controller public class FileController { //将name=file得到的文件封装成CommonsMultipartFile对象,如果是批量上传将其改成数组即可 @RequestMapping("/upload") public String fileUpload(@RequestParam("file")CommonsMultipartFile file, HttpServletRequest request) throws Exception{ //获取上传文件原名 String uploadFileName=file.getOriginalFilename(); if("".equals(uploadFileName)) return "redirect:/index.jsp"; //上传路径保存 String path= request.getServletContext().getRealPath("/upload"); //如果路径不存在创建文件路径 File realPath=new File(path); if(!realPath.exists()){ realPath.mkdir(); } //获取上传文件输入流 InputStream in=file.getInputStream(); //创建文件输出流 OutputStream outputStream=new FileOutputStream(new File(realPath,uploadFileName)); int len=0; byte[] buffer=new byte[1024]; while((len=in.read())!=-1){ outputStream.write(buffer,0,len); outputStream.flush(); } outputStream.close(); in.close(); return "redirect:/index.jsp"; } }
也可以直接采用transferTo()来保存上传文件
@Controller public class FileController { //将name=file得到的文件封装成CommonsMultipartFile对象,如果是批量上传将其改成数组即可 @RequestMapping("/upload") public String fileUpload(@RequestParam("file")CommonsMultipartFile file, HttpServletRequest request) throws Exception{ //获取上传文件原名 String uploadFileName=file.getOriginalFilename(); if("".equals(uploadFileName)) return "redirect:/index.jsp"; //上传路径保存 String path= request.getServletContext().getRealPath("/upload"); //如果路径不存在创建文件路径 File realPath=new File(path); if(!realPath.exists()){ realPath.mkdir(); } //上传保存的路径 File path1=new File(realPath+"/"+uploadFileName); System.out.println(path1.toString()); file.transferTo(path1); return "redirect:/index.jsp"; } }
文件下载
@RequestMapping("/download") public String downloads(HttpServletRequest request, HttpServletResponse response) throws Exception{ //下载图片地址 String path=request.getServletContext().getRealPath("/upload"); String fileName="2.PNG"; //设置响应头 response.reset();//设置页面不缓存 response.setCharacterEncoding("utf-8"); response.setContentType("multipart/form-data"); //设置响应头 response.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8")); File file=new File(path,fileName); System.out.println(file.toString()); //创建读取文件的输入流 InputStream inputStream=new FileInputStream(file); //写出文件输出流 OutputStream outputStream=response.getOutputStream(); int len=0; byte[] buff=new byte[1024]; while((len=inputStream.read(buff))!=-1){ outputStream.write(buff,0,len); outputStream.flush(); } outputStream.close(); inputStream.close(); return null; }