M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
1. @RequestMapping注解
:Spring MVC封装的请求处理拦截器,类似Servlet中的@WebFilter,接收请求
:匹配请求,拦截、过滤请求
:需要相关配置
1.1 位置:
放在方法前:则请求路径为hostlost:8080/testRequestMapping
public class RequestMappingController { //此时请求映射所映射的请求的请求路径为:hostlost:8080/testRequestMapping @RequestMapping("/testRequestMapping") public String testRequestMapping(){ return "success"; } }
放类前:请求路径有变化,需写正确才会接受请求
@Controller @RequestMapping("/test") public class RequestMappingController { //此时请求映射所映射的请求的请求路径为:/test/testRequestMapping @RequestMapping("/testRequestMapping") public String testRequestMapping(){ return "success"; } }
1.2 属性
value属性:
:指定请求的资源路径,可以是数组,
<a th:href="@{/testRequestMapping}">测试@RequestMapping的value属性-->/testRequestMapping</a><br>
@RequestMapping(value = "/testRequestMapping")
public String testRequestMapping(){
return "success";
}
页面点击链接,发送请求/testRequestMapping,Spring MVC接收到请求,匹配有@RequestMapping注解的value值,使用匹配的方法进行处理
method属性: 指明请求是get还是post才接收,也是数组
@RequestMapping(
value = {"/testRequestMapping", "/test"},
method = {RequestMethod.GET, RequestMethod.POST}
)
public String testRequestMapping(){
return "success";
}
params和headers属性: 指明请求带参数和请求头的参数
1.3 支持 ant 风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符
**:表示任意的一层或多层目录
如下,/a3a可被接收,/aea也可以被接受
<a th:href="@{/a3a}">测试@RequestMapping的value属性-->/testRequestMapping</a><br>
@RequestMapping(value = "/a?a")
public String testRequestMapping(){
return "success";
}
1.4 支持路径中的占位符
:使用{ }标明
:使用@PathVariable注解获取
如下,接收/testRest/1/tom
的请求,可获取 1 和 tom
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){
System.out.println("id:"+id+",username:"+username);
return "success";
}
//最终输出的内容为-->id:1,username:admin
2. 获取请求参数
2.1 Servlet API获取(少用)
类似原生的Servlet
方法
@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){ //自动获取请求体对象
String username = request.getParameter("username"); //使用HttpServletRequest的方法
String password = request.getParameter("password"); //获取请求体中的信息
System.out.println("username:"+username+",password:"+password);
return "success";
}
2.2 控制器直接获取
<a th:href="@{/testParam(username='admin',password=123456)}"></a><br>
@RequestMapping("/testParam") //名字必须和请求体中的键名一样
public String testParam(String username, String password){ //自动匹配同名参数
System.out.println("username:"+username+",password:"+password);
return "success";
}
2.3 注解获取信息
@RequestParam:获取请求参数
@RequestHeader:获取请求头信息
@CookieValue:获取请求体中的Cookie数据
2.4 通过POJO实体类获取
如下例子:表单提交多个信息,定义的实体类User中有id、name、pwd等属性
<form th:action="@{/testpojo}" method="post">
id、name、pwd、等
<input type="submit">
</form>
可以用实体类的对象进行数据的接收
@RequestMapping("/testpojo")
public String testPOJO(User user){ //自动接收form提交的数据
System.out.println(user);
return "success";
}
//最终结果-->User{id=null, username='张三', password='123', age=23, sex='男', email='123@qq.com'}
3. 域共享数据
3.1 request 域
使用 ModelAndView 向 request 域对象共享数据
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//向请求域共享数据
//testScope键,hello,ModelAndView值
//同域内对象可以通过testScope键获取值,实现共享
mav.addObject("testScope", "hello,ModelAndView");
//设置视图,实现页面跳转
mav.setViewName("success");
return mav;
}
同域--前端获取数据,使用"${}"
来获取指定键对应的值
<p th:text="${testScope}"></p>
:还有Model、ModelMap、Map方法实现共享
3.2 其他域共享
可以向session、application域的共享数据
4. 视图控制
:指html,页面
4.1 ThymeleafView
:当控制器方法中所设置的视图名称没有任何前缀时,默认使用配置文件中所配置的视图解析器解析来跳转视图
@RequestMapping("/testHello")
public String testHello(){
return "hello"; //默认解析,跳转到hello.html视图
}
4.2 转发视图
加上forward:
前缀,则不会被视图解析器解析,会通过转发方式实现
@RequestMapping("/testForward")
public String testForward(){
return "forward:/testHello"; //转发跳转到testHello
}
4.3 重定向
加上redirect:
前缀
return "redirect:/testHello";
4.4 视图控制器
:当控制器方法内只实现页面跳转时,可以用view-controller
标签 配置来控制
如ThymeleafView
中的例子可以用配置
<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>
<!--不添加这句,则视图解析器失效,所以要添加这句-->
<mvc:annotation-driven />
view-name的值也按ThymeleafView、转发、重定向的三种规则填,即可以填forward等前缀
5. RESTful API
:提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性
:一种接口设定的规范,思想,非新技术
如下,传统请求方式 getUserById?id=1 带动词,带?传参
REST风格则是规定用 / 代替?,用GET、POST、PUT、DELETE请求方式来告诉后端请求要进行增删查改
5.1 如何发送delete、put请求
浏览器只能发送get、post请求,需要在 web.xml 配置过滤器,将post请求转换为delete、put请求
:在web.xml中注册HiddenHttpMethodFilter
:在web.xml中注册时,必须先注册CharacterEncodingFilter
(乱码过滤器),再注册HiddenHttpMethodFilter
请求经过HiddenHttpMethodFilter
的条件:
必须是post请求
请求中必须指定传输请求参数
_method
,并指定值为delete或put
<form id="delete_form" method="post">
<!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 -->
<input type="hidden" name="_method" value="delete"/>
</form>
5.2 例子
实现以下接口
注意:URL地址一样,但请求方式不同,则@RequestMapping匹配到的方法也不同
查询全部数据:
前端:
<!--超链接默认是GET请求-->
<a th:href="@{/employee}">访问员工信息</a>
后端:
@RequestMapping(value = "/employee", method = RequestMethod.GET)
public String getEmployeeList(Model model){/**/}
删除:
<form id="delete_form" method="post">
<!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 -->
<input type="hidden" name="_method" value="delete"/>
</form>
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){/**/}
执行保存:
<form th:action="@{/employee}" method="post">
lastName:<input type="text" name="lastName"><br>
email:<input type="text" name="email"><br>
gender:<input type="radio" name="gender" value="1">male
<input type="radio" name="gender" value="0">female<br>
<input type="submit" value="add"><br>
</form>
@RequestMapping(value = "/employee", method = RequestMethod.POST)
public String addEmployee(Employee employee){}
6. 响应体信息
HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity来处理请求和响应
6.1 @ResponseBody响应体
作用:将方法的返回数据作响应体返回
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
return "success";
}
6.2 处理Json数据
导入jackson的依赖
Spring MVC配置中配置<mvc:annotation-driven />消息转换器,来将java对象转换Json数据
使用@ResponseBody注解
@RequestMapping("/testResponseUser") @ResponseBody //返回User对象,消息转换器会将User转换为Json数据 public User testResponseUser(){ return new User(1001,"admin","123456",23,"男"); }
浏览器的页面中展示的结果:
{"id":1001,"username":"admin","password":"123456","age":23,"sex":"男"}
6.3 Spring MVC 接收 Ajax
后端接口一样,代码类似
@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username, String password){ //获取Ajax的参数
System.out.println("username:"+username+",password:"+password);
return "hello,ajax";
}
6.4 其他同类注解
@RequestBody:获取请求体,放在形参中
@RequestEntity:封装请求报文,可以获取请求头、请求体等信息
@RestController:复合注解,放在类上,相当于给类添加@Controller、@ResponseBody注解
@ResponseEntity:控制返回值类型,即响应报文,比ResponseBody用处更广,更常用
7. 文件的上传和下载
7.1 下载
只有/static/img/1.jpg
和attachment;filename=1.jpg
里面的1.jpg可以改,其他都可以固定照抄
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
//创建输入流
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=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
7.2 上传
@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//处理文件重名问题
String hzName = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString() + hzName;
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
//如果文件夹不存在,则创建文件夹
if(!file.exists()){
file.mkdir();
}
//File.separator是 /
String finalPath = photoPath + File.separator + fileName;
//实现上传功能
photo.transferTo(new File(finalPath));
return "success";
}
8. 拦截器
:类似过滤器,执行于控制器方法前
在bean中配置拦截器,并设定拦截范围
<mvc:interceptor> <!--拦截范围--> <mvc:mapping path="/**"/> <!--不拦截的范围--> <mvc:exclude-mapping path="/testRequestEntity"/> <!--指定拦截器类--> <ref bean="firstInterceptor"></ref> </mvc:interceptor>
创建拦截器类
@Component public class firstInterceptor implements HandlerInterceptor {}
重写preHandle、postHandle、afterComplation三个方法
preHandle:控制器方法执行之前执行preHandle,返回true为放行,执行控制器方法,反之不放行,不执行控制器方法
postHandle:控制器方法执行之后执行,不放行,则控制器方法不执行,即该方法不执行
afterComplation:渲染视图完毕之后执行
多个拦截器执行顺序:
preHandle按顺序执行,postHandle、afterComplation倒序执行
如5个拦截器,第1,2个放行,第3个不放行,则执行顺序如下:
1 preHandle true
2 preHandle true
3 preHandle false
2 afterComplation
1 afterComplation
有一个preHandle返回false则所有postHandle都不执行,因为控制器方法不执行
afterComplation则有返回true的就执行
9. 异常处理
:可以用来当发生异常时,跳转到自定义页面,并在页面输出异常的信息
基于配置的异常处理:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--
exceptionMappings固定注入的属性
key填异常类
后面的error表示跳转到自定义的error.html页面
-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!--
exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
基于注解方式的异常处理:略
10.注解配置MVC
使用配置类和注解代替web.xml和SpringMVC配置文件的功能
:类似创建一个类来配置Spring
11. SpringMVC执行流程
DispatcherServlet:前端控制器,不需要工程师开发,由框架提供
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
HandlerMapping:处理器映射器,不需要工程师开发,由框架提供
作用:根据请求的url、method等信息查找Handler,即控制器方法
Handler:处理器,需要工程师开发
作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
作用:通过HandlerAdapter对处理器(控制器方法)进行执行
ViewResolver:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
View:视图
作用:将模型数据通过页面展示给用户
流程:
1、请求首先进入DispatcherServlet
, 由DispatcherServlet
从HandlerMappings
中匹配对应的Handler
,此时只是获取到了对应的Handler
,然后拿着这个Handler
去寻找对应的适配器,即:HandlerAdapter
;
2、拿到对应HandlerAdapter
时,这时候开始调用对应的Handler
方法,即执行我们的Controller
来处理业务逻辑了, 执行完成之后返回一个ModeAndView
;
3、HandlerAdapter
执行完之后,返回一个ModeAndView
,把它交给我们的视图解析器ViewResolver
,通过视图名称查找出对应的视图然后返回;
4、最后,渲染视图 返回渲染后的视图。