spring整合mybatis

  1. 对于spring项目中整合mybatsi前置条件:导入spring本身的依赖,以及mybatis的依赖,还需要多导入一个整合mybatisspring的依赖(mybatis提供的)。

1、导入依赖:spring-context spring-jdbc mybatis-spring mybatis mysql-connector-java druid lombok

2、编写spring的配置文件

a)扫描包下的注解(spring本身的注解)

b)配置数据库连接池(druid)

c)SqlSessionFactoryBean(注入一个datasource)

d)MapperScannerConfigurer 指定扫描的包(basepackage:扫描创建mapper接口的代理对象)

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
  7. <context:component-scan base-package="com.woniuxy"/>
  8. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
  9. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  10. <property name="url" value="jdbc:mysql:///bank?characterEncoding=utf-8&amp;useSSL=false"/>
  11. <property name="username" value="root"/>
  12. <property name="password" value="root"/>
  13. </bean>
  14. <!--
  15. 配置sqlSessionFactoryBean
  16. 作用:产生一个sqlsessionfactory 只要ioc容器中有任何一个bean需要使用sqlsession,
  17. 那么就会由sqlsessionfactory自动创建一个给其使用。
  18. -->
  19. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  20. <property name="dataSource" ref="dataSource"/>
  21. <!-- <property name="configLocation" value="classpath:sqlConfig.xml"/>-->
  22. </bean>
  23. <!--
  24. 配置MapperScannerConfigurer:
  25. 作用:用于扫描指定的包,创建对应接口的代理对象
  26. -->
  27. <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  28. <property name="basePackage" value="com.woniuxy.mapper"/>
  29. </bean>
  30. </beans>

spingmvc

mvc: m model v view c controller

Spring MVC 的请求流程:
执行流程2.png

入门案例的实现

1、导入依赖,如果配置dispatcherServlet报错,再导入servlet-api依赖即可

  1. <!--1、springmvc的依赖-->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.2.8.RELEASE</version>
  6. </dependency>

2、配置前端控制器dispatcherServlet

  1. <!--2、配置DispatcherServlet-->
  2. <servlet>
  3. <servlet-name>springmvc</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <!-- 修改springmvc项目的配置文件名称及路径 -->
  6. <init-param>
  7. <param-name>contextConfigLocation</param-name>
  8. <param-value>classpath:springmvc.xml</param-value>
  9. </init-param>
  10. </servlet>
  11. <servlet-mapping>
  12. <servlet-name>springmvc</servlet-name>
  13. <!-- 如果使用/拦截所有请求,那么今后一定要进行静态资源映射 -->
  14. <url-pattern>/</url-pattern>
  15. </servlet-mapping>

3、编写控制器

  1. /**
  2. * controller就相当于web项目中的servlet,用于接收请求,作出响应
  3. */
  4. @Controller
  5. public class UserController {
  6. // http://localhost:8080/hello
  7. @RequestMapping("/hello")
  8. public String hello(){
  9. System.out.println("hello springmvc");
  10. return "main";//逻辑视图名
  11. }
  12. }

4、编写springmvc配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. https://www.springframework.org/schema/context/spring-context.xsd">
  9. <!--扫描@Controller注解-->
  10. <context:component-scan base-package="com.woniuxy.controller"/>
  11. <!--配置springmvc的三大组件-->
  12. <!--配置映射器处理器-->
  13. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
  14. <!--配置映射器适配器-->
  15. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
  16. <!--配置视图解析器-->
  17. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  18. <!-- main -> /main.jsp -->
  19. <property name="prefix" value="/"/>
  20. <property name="suffix" value=".jsp"/>
  21. </bean>
  22. </beans>

springmvc静态资源映射

当dispatcherservlet的url-pattern设置的是”/“,拦截所有请求,此时需要对项目中的静态资源进行放行,否则访问不到。

使用mvc:resources标签进行静态资源的放行设置。

  1. <!--
  2. 静态资源映射
  3. http://localhost:8080/css/main.css
  4. mapping:用于匹配请求的url中的内容
  5. location:用于指定一个项目中的路径
  6. -->
  7. <mvc:resources mapping="/css/**" location="/css/"/>
  8. <mvc:resources mapping="/js/**" location="/js/"/>
  9. <mvc:resources mapping="/images/**" location="/images/"/>
  10. <mvc:resources mapping="/html/**" location="/html/"/>

自定义类型转换器

当spring提供的类型转换器不足以解决请求参数中传递的参数值的时候,需要使用自定义类型转换器。

1、自定义转换器需要实现一个converter接口 S:要被转换的类型 T:转换之后得到的类型

  1. public class String2Date implements Converter<String, Date> {
  2. @Override
  3. public Date convert(String source) {
  4. Date date=null;
  5. if (StringUtils.hasLength(source)) {
  6. //使用simpleDateFormat对当前字符串进行转换即可。
  7. //yyyy-MM-dd
  8. //yyyy/MM/dd
  9. String pattern1="[0-9]{4}-[0-9]{2}-[0-9]{2}";
  10. String pattern2="[0-9]{4}/[0-9]{2}/[0-9]{2}";
  11. try {
  12. if (source.matches(pattern1)) {
  13. date=new SimpleDateFormat("yyyy-MM-dd").parse(source);
  14. }
  15. if (source.matches(pattern2)) {
  16. date=new SimpleDateFormat("yyyy/MM/dd").parse(source);
  17. }
  18. } catch (ParseException e) {
  19. e.printStackTrace();
  20. }
  21. }else{
  22. //被转换的字符串为空时,进行自定义的处理。
  23. throw new RuntimeException("参数为空");
  24. }
  25. return date;
  26. }
  27. }

2、将自定义的类型转换器添加到spring提供的类型转换器集合中

  1. <!--配置自定义的类型转换器:conversionServiceFactoryBean-->
  2. <bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean">
  3. <property name="converters">
  4. <set>
  5. <bean class="com.woniuxy.converter.MyConverter"/>
  6. </set>
  7. </property>
  8. </bean>

3、将修改过后的conversionService2重新注册到spring中。

  1. <!--spring3.1.*以上版本中,使用了 <mvc:annotation-driven/>
  2. 替换了RequestMappingHandlerMapping和RequestMappingHandlerAdapter
  3. <mvc:annotation-driven>会自动注册RequestMappingHandlerMapping
  4. 与RequestMappingHandlerAdapter两个Bean,
  5. conversion-service:将变更后的conversionService重新注册给spring
  6. -->
  7. <mvc:annotation-driven conversion-service="conversionService2"/>

请求参数映射

1、简单类型的请求参数映射(String 和 基本数据类型)

需要注意的是:请求参数的名称必须和控制器方法的形参名称保持一致,否则注入不了

  1. <form action="/user/login" method="post">
  2. 用户名:<input type="text" name="username" value="tom"><br>
  3. 密码:<input type="text" name="password" value="111"><br>
  4. <input type="submit" value="登录" id="btn">
  5. </form>
  1. //请求参数映射:基本数据类型和String,直接就进行转换并注入到控制器的方法形参中
  2. //要求:方法的形参名必须和请求参数的名称保持一致,否则无法注入
  3. @RequestMapping("/user/login")
  4. public String login(User user){
  5. System.out.println(user);
  6. return "index";
  7. }

2、同名参数的映射

  1. <input type="checkbox" name="hobbies" value="eat">吃饭
  2. <input type="checkbox" name="hobbies" value="sleep">睡觉
  3. <input type="checkbox" name="hobbies" value="watch tv">看电视
  1. @RequestMapping("/login")
  2. public String login(String[] hobbies){
  3. System.out.println(hobbies.length);
  4. return "index";
  5. }
  6. @RequestMapping("/login")
  7. public String login(@RequestParam ArrayList<String> hobbies){
  8. System.out.println(hobbies);
  9. return "index";
  10. }

3、javaBean接收请求参数

要求:javaBean的成员变量名必须和请求参数名称保持一致

  1. <form action="/user/login" method="post">
  2. 用户名:<input type="text" name="username" value="tom"><br>
  3. 密码:<input type="text" name="password" value="111"><br>
  4. <input type="submit" value="登录" id="btn">
  5. </form>
  1. @Data
  2. public class User {
  3. String username;
  4. String password;
  5. }

4、ajax传递的参数

4.1 传递JSON对象时,与普通参数传递没有区别

  1. var form={
  2. username:$("#username").val(),
  3. password:$("#password").val()
  4. }
  5. $.ajax({
  6. url:"/user/realLogin",
  7. data:form,
  8. type:"post",
  9. dataType:"json",
  10. success:function (resp) {
  11. alert(resp)
  12. }
  13. })
  1. @RequestMapping("/realLogin")
  2. public String realLogin(User user){
  3. System.out.println(1111);
  4. System.out.println(user);
  5. return "";
  6. }

4.2 传递json字符串,要求是一个标准的json字符串

如果传递的是json字符串,

请求方式必须是post

请求的内容类型必须是 contentType:”application/json;charset=utf-8”

后台接收时必须使用@RequestBody

springmvc使用jackson来解析json字符串,所以必须导入相应的三个依赖。
jackson-core jackson-annotations jackson-databind

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-core</artifactId>
  4. <version>2.10.5</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.fasterxml.jackson.core</groupId>
  8. <artifactId>jackson-annotations</artifactId>
  9. <version>2.10.5</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.fasterxml.jackson.core</groupId>
  13. <artifactId>jackson-databind</artifactId>
  14. <version>2.10.5</version>
  15. </dependency>
  1. var form={
  2. username:$("#username").val(),
  3. password:$("#password").val()
  4. }
  5. //以json字符串的方式向后台传递参数
  6. //1、请求方式必须是post
  7. //2、请求的内容类型必须是 contentType:"application/json;charset=utf-8"
  8. //3、后台接收时必须使用@RequestBody 只能使用一个
  9. //4、springmvc使用jackson来解析json字符串,所以必须导入相应的三个依赖。
  10. //jackson-core jackson-annotations jackson-databind
  11. form=JSON.stringify(form)
  12. $.ajax({
  13. url:"/user/realLogin",
  14. data:form,
  15. contentType:"application/json;charset=utf-8",
  16. type:"post",
  17. dataType:"json",
  18. success:function (resp) {
  19. alert(resp)
  20. }
  21. })
  1. @RequestMapping("/realLogin")
  2. public String realLogin(@RequestBody User user){
  3. System.out.println(1111);
  4. System.out.println(user);
  5. return "";
  6. }

路径传参

restful风格的路径传参:http://localhost:8080/login/tom/111 参数存在于路径中。

不是路径传参:http://localhost:8080/login?username=tom&password=111

1、在@RequestMapping注解完整映射路径 /login/{username}/{password}

2、在参数上加@PathVariable注解

  1. @RequestMapping("testRestFul/{username}/{password}")
  2. public String testRestFul(@PathVariable String username,@PathVariable String password){
  3. System.out.println(username+":"+password);
  4. return "redirect:/html/main.html";
  5. }

注意:使用路径传参,不能再使用javaBean的形式进行参数注入。

servletAPI的获取
  1. @RequestMapping("testServletApi")
  2. public String testServletApi(HttpServletRequest request, HttpSession session){
  3. System.out.println(request);
  4. System.out.println(session);
  5. System.out.println(session.getServletContext());
  6. return "redirect:/html/main.html";
  7. }

注意:servletcontext是无法注入的

响应返回值

string:

  1. //响应回去的类型:String :逻辑视图名 物理视图(forward:请求转发 redirect:重定向)
  2. //String
  3. //逻辑视图名:一定配置视图解析器
  4. //物理视图:forward redirect关键字来实现直接的跳转。
  5. //也可以使用forward 或redirect 关键字实现控制器方法的跳转
  6. //ajax请求: JS域中发出来的 @responseBody

逻辑视图名:

  1. @RequestMapping("/login")
  2. public String login(ArrayList<String> hobbies){
  3. System.out.println(hobbies);
  4. return "index";
  5. }
  1. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  2. <property name="prefix" value="/"/>
  3. <property name="suffix" value=".html"/>
  4. </bean>

物理视图

默认请求转发,forward关键字可以省略不写

  1. //http://localhost:8080/user/testForward
  2. @RequestMapping("testForward")
  3. public String testForward(){
  4. System.out.println("请求转发");
  5. //return "/html/main.html";
  6. return "forward:/html/main.html";
  7. }

重定向

  1. //http://localhost:8080/user/testRedirect
  2. @RequestMapping("testRedirect")
  3. public String testRedirect(){
  4. System.out.println("重定向");
  5. return "redirect:/html/main.html";
  6. }

控制器方法内部跳转

  1. //http://localhost:8080/user/testRedirect
  2. @RequestMapping("testRedirect")
  3. public String testRedirect(){
  4. System.out.println("重定向");
  5. return "redirect:toLogin";
  6. }
  7. @RequestMapping("toLogin")
  8. public String toLogin(){
  9. System.out.println("重定向");
  10. return "redirect:/html/main.html";
  11. }

ajax请求: JS域中发出来的 @responseBody

  1. $(function () {
  2. $("#btn").click(function () {
  3. $.ajax({
  4. url:"/user/login",
  5. data:$("#myForm").serialize(),
  6. dataType:"json",
  7. type:"post",
  8. success:function (resp) {
  9. console.log(resp)
  10. }
  11. })
  12. })
  13. })
  1. @RequestMapping("login") //http://localhost:8080/user/login?username=tom&password=111
  2. @ResponseBody
  3. public String login(String username,String password){
  4. System.out.println(username+":"+password);
  5. // return "redirect:/html/main.html";
  6. // return "{\"msg\":\"success\"}";
  7. return new JSONObject().toJSONString("success");
  8. }

void(了解)

如果控制器方法无返回值时,会自动将请求路径中的requestMapping部分作为逻辑视图名进行相应的跳转,如果没有视图解析器,会报错,在项目中必须存在与逻辑名对应的物理视图才可以正常访问,否则404。

object 给ajax用 @ResponseBody

  1. //Object
  2. //http://localhost:8080/user/getUser?username=tom&password=111
  3. @RequestMapping("getUser")
  4. @ResponseBody
  5. //一定需要统一返回给前端的格式 dto处理 data transfer object
  6. public User getUser(User user){
  7. System.out.println(user);
  8. return user;
  9. }

统一返回给前端的数据格式 dto

dto: data transfer object

自定义一个dto

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class Result<T> {
  5. private Boolean flag;//当前端发起调用时,告诉前端此次调用实现的功能是否成功
  6. private String code;//自定义的响应状态码
  7. private String message;//封装返回给前端的消息
  8. private T data;//用于封装返回给前端的真实数据
  9. }
  1. @RequestMapping("findAll")
  2. @ResponseBody
  3. public Result findAll(){
  4. //执行了某个业务,返回一个用户数据的集合
  5. List<User> users= Arrays.asList(new User("tom","111"),new User("jack","222"));
  6. return new Result(true, StatusCode.OK,"查询用户数据成功",users);
  7. }

ModelAndView

spring提供的一个对象,可用该对象向对应的域中存储数据(model),也可使用该对象设置对应的视图(view)

  1. //ModelAndView model模型 view视图
  2. @RequestMapping("testModelAndView")
  3. public ModelAndView testModelAndView(){
  4. ModelAndView mv = new ModelAndView();
  5. mv.addObject("user",new User("tom","111"));//向model中保存数据
  6. mv.setViewName("/html/main.html");//设置视图名称
  7. return mv;
  8. }

注意的是:数据存放在request域中,如果不使用模板,是无法取得保存的数据的。

如果是前后端分离的项目,不会再使用此种方式。

restful风格的接口设计

实际项目开发中,目前基本上使用的都是前后端分离的技术,前端ajax发送rest时,后台应对应的使用restful风格去进行接口设计。

  1. restful风格的接口设计
  2. * 后台使得rest请求方式进行接口设计
  3. * rest: GET POST PUT DELETE
  4. * GET 查询
  5. * POST 新增
  6. * PUT 修改
  7. * DELETE 删除
  8. *
  9. * restful风格的接口设计:在requestmapping中不应该出现动词
  10. *
  11. * 幂等性:面试的时候可能被问到
  12. * 对同一个接口的相同操作,结果应该相同
  13. * 只有POST请求不是幂等性的,其余的GET\PUT\DELETE都是幂等性的。
  1. @Controller
  2. public class RestFulController {
  3. @RequestMapping(value="user",method= RequestMethod.GET)
  4. public String find(){
  5. System.out.println("执行了find操作");
  6. return "redirect:/html/main.html";
  7. }
  8. @RequestMapping(value = "user",method = RequestMethod.POST)
  9. public String save(){
  10. System.out.println("执行了save操作");
  11. return "redirect:/html/main.html";
  12. }
  13. @RequestMapping(value = "user",method = RequestMethod.PUT)
  14. public String update(){
  15. System.out.println("执行了update操作");
  16. return "redirect:/html/main.html";
  17. }
  18. @RequestMapping(value = "user",method = RequestMethod.DELETE)
  19. public String delete(){
  20. System.out.println("执行了delete操作");
  21. return "redirect:/html/main.html";
  22. }
  23. }

测试时,可以使用postman或者发送$.ajax({type:GET|POST|PUT|DELETE}),也可以使用idea提供的测试工具

tools->http client->test restful web service

异常

自定义异常处理器

实现一个handlerExceptionResolver接口,注意,自定义异常处理器只要注册到容器中,会自动生效。

  1. /**
  2. * 自定义异常处理器
  3. */
  4. @Component
  5. public class CustomerExceptionHandler implements HandlerExceptionResolver {
  6. @Override
  7. publ
  8. +-ic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
  9. //看看用户发送的请求是否是ajax请求,如果是,处理的方式一定和普通形式的请求是不一样的。
  10. ModelAndView mv = new ModelAndView();
  11. if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
  12. //ajax请求
  13. //创建json视图,使用的是fastJson
  14. FastJsonJsonView jsonView = new FastJsonJsonView();
  15. HashMap<String, Object> map = new HashMap<>();
  16. map.put("message","服务器繁忙");
  17. jsonView.setAttributesMap(map);
  18. mv.setView(jsonView);
  19. }else{
  20. mv.setViewName("/html/error.html");
  21. }
  22. return mv;
  23. }
  24. }

全局异常总类

  1. @RestControllerAdvice
  2. public class GlobalExceptionHandler {
  3. //全局异常总类中的编写规则:
  4. // 一定会有一个处理Exception类的方法兜底
  5. // 在异常总类中,对某一个具体的异常进行处理。
  6. @ExceptionHandler(NullPointerException.class)
  7. public Result handlerNullPointException(){
  8. return new Result(false,"20002","空指针异常",null);
  9. }
  10. @ExceptionHandler(ArithmeticException.class)
  11. public Result handlerArithmeticException(){
  12. return new Result(false,"20003","算术异常",null);
  13. }
  14. @ExceptionHandler(Exception.class)
  15. public Result handlerException(){
  16. return new Result(false,"20001","服务器异常",null);
  17. }
  18. }

使用@RestController代替@Controller和@ResponseBody

  1. //使用了@RestController注解,一定没有办法进行页面跳转。

在使用restful风格进行接口设计时

使用@(Get|Post|Put|Delete)Mapping代替@RequestMapping(value=”user”,method= RequestMethod.GET|POST|PUT|DELETE)

参数校验

对于提交到后台的参数,会做两步验证:第一步验证发生在前端表单提交时,第二步验证发生在后台参数注入的时候。

JSR303方式进行的参数校验,官方推荐的实践:hibernate-validator

导入依赖

  1. <dependency>
  2. <groupId>org.hibernate.validator</groupId>
  3. <artifactId>hibernate-validator</artifactId>
  4. <version>6.1.5.Final</version>
  5. </dependency>

控制器方法中使用javaBean来接收请求参数,在javaBean的成员变量上使用对应的注解,来对注入的参数值进行校验。

  1. @Data
  2. public class User {
  3. @NotNull(message = "用户名不能为空")
  4. @Length(min = 10,max = 16,message = "用户名长度必须在10-16之间")
  5. @Pattern(regexp = "[a-zA-Z]\\w+",message = "用户名不能以数字开头")
  6. private String username;
  7. @NotNull(message = "密码不能为空")
  8. @Length(min = 6,max = 8,message = "长度只能在6-8之间")
  9. private String password;
  10. @NotNull(message = "邮箱不能为空")
  11. @Pattern(regexp= "\\w{1,15}@\\w{1,15}(.\\w{2,3}){1,2}",message = "邮箱格式不正确")
  12. private String email;
  13. }

控制器中使用@valid注解对参数注入的值进行校验,校验结果保存在bindingResult中,请注意:bindingResult只能紧跟在要校验的对象之后。

  1. @PostMapping
  2. @ResponseBody
  3. public Result register(@Valid User user, BindingResult bindingResult) throws ParameterValidetorException {
  4. //判断验证结果中,是否有错误,如果有错误,意味着参数验证没通过
  5. if (bindingResult.hasErrors()) {
  6. throw new ParameterValidetorException();
  7. }
  8. System.out.println(user);
  9. return new Result(true, StatusCode.OK,"注册成功",null);
  10. }

拦截器

拦截器是springmvc中一个强大的控件,它的功能有点类似于过滤器。拦截器的作用时期是在前端控制器(dispatcherservlet)和被@Controller注解的控制器之间。

捕获.PNG
在springmvc中,如果要创建拦截器,需要实现一个接口:handlerInterceptor。实现业务时,主要关注:preHandle(),此方法决定是请求是否能向下一步进入到controller中。

步骤1:创建拦截器

  1. /**
  2. * 只要实现了HandlerInterceptor接口,当前类就会是一个拦截器
  3. */
  4. public class FirstInterceptor implements HandlerInterceptor {
  5. /**
  6. * 前置处理:在业务控制器方法执行之前执行的
  7. * 根据preHandle方法的返回值,决定是否放行 true 放行 false 拦截
  8. * @param request
  9. * @param response
  10. * @param handler
  11. * @return
  12. * @throws Exception
  13. */
  14. @Override
  15. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  16. System.out.println("FirstInterceptor的preHandle执行了");
  17. //放行
  18. return true;
  19. }
  20. /**
  21. * 后置处理:在控制器方法执行之后再执行的
  22. * @param request
  23. * @param response
  24. * @param handler
  25. * @param modelAndView
  26. * @throws Exception
  27. */
  28. @Override
  29. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  30. System.out.println("FirstInterceptor的postHandle执行了");
  31. }
  32. /**
  33. * 渲染视图完成之后执行的
  34. * @param request
  35. * @param response
  36. * @param handler
  37. * @param ex
  38. * @throws Exception
  39. */
  40. @Override
  41. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  42. System.out.println("FirstInterceptor的afterCompletion执行了");
  43. }
  44. }

步骤2:配置拦截器

  1. <!--开启拦截器配置-->
  2. <mvc:interceptors>
  3. <!--配置某个拦截器,该配置可以有多个-->
  4. <mvc:interceptor>
  5. <!--mvc:mapping:用于配置被拦截器拦截的请求资源 黑名单 -->
  6. <mvc:mapping path="/**"/>
  7. <!--mvc:exclude-mapping:用于配置不被拦截器拦截的请求资源 白名单 -->
  8. <mvc:exclude-mapping path="/"/>
  9. <mvc:exclude-mapping path="/user/login"/>
  10. <mvc:exclude-mapping path="/user/register"/>
  11. <mvc:exclude-mapping path="/html/login.html"/>
  12. <mvc:exclude-mapping path="/html/register.html"/>
  13. <mvc:exclude-mapping path="/css/*"/>
  14. <mvc:exclude-mapping path="/js/*"/>
  15. <mvc:exclude-mapping path="/images/*"/>
  16. <!--配置使用哪个拦截器来处理被拦截的资源-->
  17. <bean class="com.woniuxy.interceptor.FirstInterceptor"/>
  18. </mvc:interceptor>
  19. </mvc:interceptors>

拦截器链的执行顺序由配置文件中的拦截器配置顺序来决定。

拦截器应用 登录验证

  1. public class LoginInterceptor implements HandlerInterceptor {
  2. @Override
  3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  4. //登录验证
  5. //判断session中是保存了登录状态
  6. Object loginUser = request.getSession().getAttribute("loginUser");
  7. if (ObjectUtils.isEmpty(loginUser)) {
  8. response.setCharacterEncoding("utf-8");
  9. response.setContentType("text/html;charset=utf-8");
  10. response.getWriter().write("当前用户尚未登录");
  11. //拦截
  12. return false;
  13. }
  14. return true;
  15. }
  16. }
  1. <!--开启拦截器配置-->
  2. <mvc:interceptors>
  3. <mvc:interceptor>
  4. <mvc:mapping path="/**"/>
  5. <mvc:exclude-mapping path="/"/>
  6. <mvc:exclude-mapping path="/user/login"/>
  7. <mvc:exclude-mapping path="/user/register"/>
  8. <mvc:exclude-mapping path="/html/login.html"/>
  9. <mvc:exclude-mapping path="/html/register.html"/>
  10. <mvc:exclude-mapping path="/css/*"/>
  11. <mvc:exclude-mapping path="/js/*"/>
  12. <mvc:exclude-mapping path="/images/*"/>
  13. <bean class="com.woniuxy.interceptor.LoginInterceptor"/>
  14. </mvc:interceptor>
  15. </mvc:interceptors>

ssm整合 (spring springmvc mybatis)

整合时如果不考虑父子容器的问题,就一定导致一个后果:声明式事务失效。

父子容器

让spring扫描service

让springmvc扫描controller

整合实现

spring整合mybatis

与之前的配置一样。

spring整合springmvc

1、web.xml配置,让web容器启动时先创建父容器,后创建子容器。

  1. <!DOCTYPE web-app PUBLIC
  2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
  4. <web-app>
  5. <display-name>Archetype Created Web Application</display-name>
  6. <!--加载类路径下的xml文件创建父容器-->
  7. <context-param>
  8. <param-name>contextConfigLocation</param-name>
  9. <param-value>classpath:applicationContext.xml</param-value>
  10. </context-param>
  11. <!--监听servletContext对象的创建-->
  12. <listener>
  13. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  14. </listener>
  15. <!-- 创建dispatcherservlet时,创建子容器 -->
  16. <servlet>
  17. <servlet-name>springmvc</servlet-name>
  18. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  19. <init-param>
  20. <param-name>contextConfigLocation</param-name>
  21. <param-value>classpath:springmvc.xml</param-value>
  22. </init-param>
  23. </servlet>
  24. <servlet-mapping>
  25. <servlet-name>springmvc</servlet-name>
  26. <url-pattern>/</url-pattern>
  27. </servlet-mapping>
  28. </web-app>

2、配置spring和springmvc各自扫描的包

让spring扫描service

  1. <context:component-scan base-package="com.woniuxy.service"/>

让springmvc扫描controller

  1. <context:component-scan base-package="com.woniuxy.controller"/>

此时整合即已完成。

SSM整合及声明式事务:

applicationContext.xml spring配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4. xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
  7. <context:component-scan base-package="com.woniuxy.service"/>
  8. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
  9. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  10. <property name="url" value="jdbc:mysql:///bank?characterEncoding=utf-8&amp;useSSL=false"/>
  11. <property name="username" value="root"/>
  12. <property name="password" value="root"/>
  13. </bean>
  14. <!--
  15. 配置sqlSessionFactoryBean
  16. 作用:产生一个sqlsessionfactory 只要ioc容器中有任何一个bean需要使用sqlsession,
  17. 那么就会由sqlsessionfactory自动创建一个给其使用。
  18. -->
  19. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  20. <property name="dataSource" ref="dataSource"/>
  21. <!-- <property name="configLocation" value="classpath:sqlConfig.xml"/>-->
  22. </bean>
  23. <!--
  24. 配置MapperScannerConfigurer:
  25. 作用:用于扫描指定的包,创建对应接口的代理对象
  26. -->
  27. <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  28. <property name="basePackage" value="com.woniuxy.mapper"/>
  29. </bean>
  30. <!--配置事务管理器-->
  31. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  32. <property name="dataSource" ref="dataSource"/>
  33. </bean>
  34. <!-- 对声明式事务的注解提供支持 -->
  35. <tx:annotation-driven/>
  36. </beans>

springmvc.xml springmvc配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mvc="http://www.springframework.org/schema/mvc"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. https://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/mvc
  11. https://www.springframework.org/schema/mvc/spring-mvc.xsd">
  12. <context:component-scan base-package="com.woniuxy.controller"/>
  13. <mvc:annotation-driven/>
  14. <!-- <mvc:resources mapping="/js/**" location="/js/"/>-->
  15. <mvc:resources mapping="/html/**" location="/html/"/>
  16. </beans>

数据访问层

  1. public interface AccountMapper {
  2. @Select("select * from account where username=#{username}")
  3. Account findByUserName(String username);
  4. @Update("update account set balance=#{balance} where username=#{username}")
  5. int updateAccount(Account account);
  6. }

业务层

  1. @Service("accountService")
  2. @Transactional
  3. public class AccountServiceImpl implements AccountService {
  4. @Resource
  5. private AccountMapper accountMapper;
  6. @Override
  7. public void transfer(TransferVo transferVo){
  8. //查询要进行转帐操作的两个人的帐户信息
  9. Account sourceAccount = accountMapper.findByUserName(transferVo.getSource());
  10. Account targetAccount = accountMapper.findByUserName(transferVo.getTarget());
  11. //判断被转出人的帐户余额是否足够
  12. if (sourceAccount.getBalance()>transferVo.getMoney()) {
  13. //真正执行转账操作
  14. sourceAccount.setBalance(sourceAccount.getBalance()-transferVo.getMoney());
  15. targetAccount.setBalance(targetAccount.getBalance()+transferVo.getMoney());
  16. accountMapper.updateAccount(sourceAccount);
  17. System.out.println(1/0);
  18. accountMapper.updateAccount(targetAccount);
  19. }
  20. }
  21. }

控制层

  1. @Controller
  2. public class AccountController {
  3. @Resource
  4. private AccountService accountService;
  5. @RequestMapping("account/transfer")
  6. @ResponseBody
  7. public Result transfer(TransferVo transferVo){
  8. accountService.transfer(transferVo);
  9. return new Result(true, StatusCode.OK,"转账成功",null);
  10. }
  11. }