spring整合mybatis
对于spring项目中整合mybatsi前置条件:导入spring本身的依赖,以及mybatis的依赖,还需要多导入一个整合mybatis与spring的依赖(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接口的代理对象)
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.woniuxy"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///bank?characterEncoding=utf-8&useSSL=false"/><property name="username" value="root"/><property name="password" value="root"/></bean><!--配置sqlSessionFactoryBean作用:产生一个sqlsessionfactory 只要ioc容器中有任何一个bean需要使用sqlsession,那么就会由sqlsessionfactory自动创建一个给其使用。--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><!-- <property name="configLocation" value="classpath:sqlConfig.xml"/>--></bean><!--配置MapperScannerConfigurer:作用:用于扫描指定的包,创建对应接口的代理对象--><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.woniuxy.mapper"/></bean></beans>
spingmvc
mvc: m model v view c controller
Spring MVC 的请求流程:
入门案例的实现
1、导入依赖,如果配置dispatcherServlet报错,再导入servlet-api依赖即可
<!--1、springmvc的依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.8.RELEASE</version></dependency>
2、配置前端控制器dispatcherServlet
<!--2、配置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.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><!-- 如果使用/拦截所有请求,那么今后一定要进行静态资源映射 --><url-pattern>/</url-pattern></servlet-mapping>
3、编写控制器
/*** controller就相当于web项目中的servlet,用于接收请求,作出响应*/@Controllerpublic class UserController {// http://localhost:8080/hello@RequestMapping("/hello")public String hello(){System.out.println("hello springmvc");return "main";//逻辑视图名}}
4、编写springmvc配置文件
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!--扫描@Controller注解--><context:component-scan base-package="com.woniuxy.controller"/><!--配置springmvc的三大组件--><!--配置映射器处理器--><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/><!--配置映射器适配器--><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/><!--配置视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- main -> /main.jsp --><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean></beans>
springmvc静态资源映射
当dispatcherservlet的url-pattern设置的是”/“,拦截所有请求,此时需要对项目中的静态资源进行放行,否则访问不到。
使用mvc:resources标签进行静态资源的放行设置。
<!--静态资源映射http://localhost:8080/css/main.cssmapping:用于匹配请求的url中的内容location:用于指定一个项目中的路径--><mvc:resources mapping="/css/**" location="/css/"/><mvc:resources mapping="/js/**" location="/js/"/><mvc:resources mapping="/images/**" location="/images/"/><mvc:resources mapping="/html/**" location="/html/"/>
自定义类型转换器
当spring提供的类型转换器不足以解决请求参数中传递的参数值的时候,需要使用自定义类型转换器。
1、自定义转换器需要实现一个converter接口 S:要被转换的类型 T:转换之后得到的类型
public class String2Date implements Converter<String, Date> {@Overridepublic Date convert(String source) {Date date=null;if (StringUtils.hasLength(source)) {//使用simpleDateFormat对当前字符串进行转换即可。//yyyy-MM-dd//yyyy/MM/ddString pattern1="[0-9]{4}-[0-9]{2}-[0-9]{2}";String pattern2="[0-9]{4}/[0-9]{2}/[0-9]{2}";try {if (source.matches(pattern1)) {date=new SimpleDateFormat("yyyy-MM-dd").parse(source);}if (source.matches(pattern2)) {date=new SimpleDateFormat("yyyy/MM/dd").parse(source);}} catch (ParseException e) {e.printStackTrace();}}else{//被转换的字符串为空时,进行自定义的处理。throw new RuntimeException("参数为空");}return date;}}
2、将自定义的类型转换器添加到spring提供的类型转换器集合中
<!--配置自定义的类型转换器:conversionServiceFactoryBean--><bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><set><bean class="com.woniuxy.converter.MyConverter"/></set></property></bean>
3、将修改过后的conversionService2重新注册到spring中。
<!--spring3.1.*以上版本中,使用了 <mvc:annotation-driven/>替换了RequestMappingHandlerMapping和RequestMappingHandlerAdapter<mvc:annotation-driven>会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两个Bean,conversion-service:将变更后的conversionService重新注册给spring--><mvc:annotation-driven conversion-service="conversionService2"/>
请求参数映射
1、简单类型的请求参数映射(String 和 基本数据类型)
需要注意的是:请求参数的名称必须和控制器方法的形参名称保持一致,否则注入不了。
<form action="/user/login" method="post">用户名:<input type="text" name="username" value="tom"><br>密码:<input type="text" name="password" value="111"><br><input type="submit" value="登录" id="btn"></form>
//请求参数映射:基本数据类型和String,直接就进行转换并注入到控制器的方法形参中//要求:方法的形参名必须和请求参数的名称保持一致,否则无法注入@RequestMapping("/user/login")public String login(User user){System.out.println(user);return "index";}
2、同名参数的映射
<input type="checkbox" name="hobbies" value="eat">吃饭<input type="checkbox" name="hobbies" value="sleep">睡觉<input type="checkbox" name="hobbies" value="watch tv">看电视
@RequestMapping("/login")public String login(String[] hobbies){System.out.println(hobbies.length);return "index";}或@RequestMapping("/login")public String login(@RequestParam ArrayList<String> hobbies){System.out.println(hobbies);return "index";}
3、javaBean接收请求参数
要求:javaBean的成员变量名必须和请求参数名称保持一致
<form action="/user/login" method="post">用户名:<input type="text" name="username" value="tom"><br>密码:<input type="text" name="password" value="111"><br><input type="submit" value="登录" id="btn"></form>
@Datapublic class User {String username;String password;}
4、ajax传递的参数
4.1 传递JSON对象时,与普通参数传递没有区别
var form={username:$("#username").val(),password:$("#password").val()}$.ajax({url:"/user/realLogin",data:form,type:"post",dataType:"json",success:function (resp) {alert(resp)}})
@RequestMapping("/realLogin")public String realLogin(User user){System.out.println(1111);System.out.println(user);return "";}
4.2 传递json字符串,要求是一个标准的json字符串
如果传递的是json字符串,
请求方式必须是post
请求的内容类型必须是 contentType:”application/json;charset=utf-8”
后台接收时必须使用@RequestBody
springmvc使用jackson来解析json字符串,所以必须导入相应的三个依赖。
jackson-core jackson-annotations jackson-databind
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.10.5</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.10.5</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.5</version></dependency>
var form={username:$("#username").val(),password:$("#password").val()}//以json字符串的方式向后台传递参数//1、请求方式必须是post//2、请求的内容类型必须是 contentType:"application/json;charset=utf-8"//3、后台接收时必须使用@RequestBody 只能使用一个//4、springmvc使用jackson来解析json字符串,所以必须导入相应的三个依赖。//jackson-core jackson-annotations jackson-databindform=JSON.stringify(form)$.ajax({url:"/user/realLogin",data:form,contentType:"application/json;charset=utf-8",type:"post",dataType:"json",success:function (resp) {alert(resp)}})
@RequestMapping("/realLogin")public String realLogin(@RequestBody User user){System.out.println(1111);System.out.println(user);return "";}
路径传参
restful风格的路径传参:http://localhost:8080/login/tom/111 参数存在于路径中。
不是路径传参:http://localhost:8080/login?username=tom&password=111
1、在@RequestMapping注解完整映射路径 /login/{username}/{password}
2、在参数上加@PathVariable注解
@RequestMapping("testRestFul/{username}/{password}")public String testRestFul(@PathVariable String username,@PathVariable String password){System.out.println(username+":"+password);return "redirect:/html/main.html";}
注意:使用路径传参,不能再使用javaBean的形式进行参数注入。
servletAPI的获取
@RequestMapping("testServletApi")public String testServletApi(HttpServletRequest request, HttpSession session){System.out.println(request);System.out.println(session);System.out.println(session.getServletContext());return "redirect:/html/main.html";}
注意:servletcontext是无法注入的
响应返回值
string:
//响应回去的类型:String :逻辑视图名 物理视图(forward:请求转发 redirect:重定向)//String//逻辑视图名:一定配置视图解析器//物理视图:forward redirect关键字来实现直接的跳转。//也可以使用forward 或redirect 关键字实现控制器方法的跳转//ajax请求: JS域中发出来的 @responseBody
逻辑视图名:
@RequestMapping("/login")public String login(ArrayList<String> hobbies){System.out.println(hobbies);return "index";}
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".html"/></bean>
物理视图
默认请求转发,forward关键字可以省略不写
//http://localhost:8080/user/testForward@RequestMapping("testForward")public String testForward(){System.out.println("请求转发");//return "/html/main.html";return "forward:/html/main.html";}
重定向
//http://localhost:8080/user/testRedirect@RequestMapping("testRedirect")public String testRedirect(){System.out.println("重定向");return "redirect:/html/main.html";}
控制器方法内部跳转
//http://localhost:8080/user/testRedirect@RequestMapping("testRedirect")public String testRedirect(){System.out.println("重定向");return "redirect:toLogin";}@RequestMapping("toLogin")public String toLogin(){System.out.println("重定向");return "redirect:/html/main.html";}
ajax请求: JS域中发出来的 @responseBody
$(function () {$("#btn").click(function () {$.ajax({url:"/user/login",data:$("#myForm").serialize(),dataType:"json",type:"post",success:function (resp) {console.log(resp)}})})})
@RequestMapping("login") //http://localhost:8080/user/login?username=tom&password=111@ResponseBodypublic String login(String username,String password){System.out.println(username+":"+password);// return "redirect:/html/main.html";// return "{\"msg\":\"success\"}";return new JSONObject().toJSONString("success");}
void(了解)
如果控制器方法无返回值时,会自动将请求路径中的requestMapping部分作为逻辑视图名进行相应的跳转,如果没有视图解析器,会报错,在项目中必须存在与逻辑名对应的物理视图才可以正常访问,否则404。
object 给ajax用 @ResponseBody
//Object//http://localhost:8080/user/getUser?username=tom&password=111@RequestMapping("getUser")@ResponseBody//一定需要统一返回给前端的格式 dto处理 data transfer objectpublic User getUser(User user){System.out.println(user);return user;}
统一返回给前端的数据格式 dto
dto: data transfer object
自定义一个dto
@Data@AllArgsConstructor@NoArgsConstructorpublic class Result<T> {private Boolean flag;//当前端发起调用时,告诉前端此次调用实现的功能是否成功private String code;//自定义的响应状态码private String message;//封装返回给前端的消息private T data;//用于封装返回给前端的真实数据}
@RequestMapping("findAll")@ResponseBodypublic Result findAll(){//执行了某个业务,返回一个用户数据的集合List<User> users= Arrays.asList(new User("tom","111"),new User("jack","222"));return new Result(true, StatusCode.OK,"查询用户数据成功",users);}
ModelAndView
spring提供的一个对象,可用该对象向对应的域中存储数据(model),也可使用该对象设置对应的视图(view)
//ModelAndView model模型 view视图@RequestMapping("testModelAndView")public ModelAndView testModelAndView(){ModelAndView mv = new ModelAndView();mv.addObject("user",new User("tom","111"));//向model中保存数据mv.setViewName("/html/main.html");//设置视图名称return mv;}
注意的是:数据存放在request域中,如果不使用模板,是无法取得保存的数据的。
如果是前后端分离的项目,不会再使用此种方式。
restful风格的接口设计
实际项目开发中,目前基本上使用的都是前后端分离的技术,前端ajax发送rest时,后台应对应的使用restful风格去进行接口设计。
restful风格的接口设计* 后台使得rest请求方式进行接口设计* rest: GET POST PUT DELETE* GET 查询* POST 新增* PUT 修改* DELETE 删除** restful风格的接口设计:在requestmapping中不应该出现动词** 幂等性:面试的时候可能被问到* 对同一个接口的相同操作,结果应该相同* 只有POST请求不是幂等性的,其余的GET\PUT\DELETE都是幂等性的。
@Controllerpublic class RestFulController {@RequestMapping(value="user",method= RequestMethod.GET)public String find(){System.out.println("执行了find操作");return "redirect:/html/main.html";}@RequestMapping(value = "user",method = RequestMethod.POST)public String save(){System.out.println("执行了save操作");return "redirect:/html/main.html";}@RequestMapping(value = "user",method = RequestMethod.PUT)public String update(){System.out.println("执行了update操作");return "redirect:/html/main.html";}@RequestMapping(value = "user",method = RequestMethod.DELETE)public String delete(){System.out.println("执行了delete操作");return "redirect:/html/main.html";}}
测试时,可以使用postman或者发送$.ajax({type:GET|POST|PUT|DELETE}),也可以使用idea提供的测试工具
tools->http client->test restful web service
异常
自定义异常处理器
实现一个handlerExceptionResolver接口,注意,自定义异常处理器只要注册到容器中,会自动生效。
/*** 自定义异常处理器*/@Componentpublic class CustomerExceptionHandler implements HandlerExceptionResolver {@Overridepubl+-ic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {//看看用户发送的请求是否是ajax请求,如果是,处理的方式一定和普通形式的请求是不一样的。ModelAndView mv = new ModelAndView();if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {//ajax请求//创建json视图,使用的是fastJsonFastJsonJsonView jsonView = new FastJsonJsonView();HashMap<String, Object> map = new HashMap<>();map.put("message","服务器繁忙");jsonView.setAttributesMap(map);mv.setView(jsonView);}else{mv.setViewName("/html/error.html");}return mv;}}
全局异常总类
@RestControllerAdvicepublic class GlobalExceptionHandler {//全局异常总类中的编写规则:// 一定会有一个处理Exception类的方法兜底// 在异常总类中,对某一个具体的异常进行处理。@ExceptionHandler(NullPointerException.class)public Result handlerNullPointException(){return new Result(false,"20002","空指针异常",null);}@ExceptionHandler(ArithmeticException.class)public Result handlerArithmeticException(){return new Result(false,"20003","算术异常",null);}@ExceptionHandler(Exception.class)public Result handlerException(){return new Result(false,"20001","服务器异常",null);}}
使用@RestController代替@Controller和@ResponseBody
//使用了@RestController注解,一定没有办法进行页面跳转。
在使用restful风格进行接口设计时
使用@(Get|Post|Put|Delete)Mapping代替@RequestMapping(value=”user”,method= RequestMethod.GET|POST|PUT|DELETE)
参数校验
对于提交到后台的参数,会做两步验证:第一步验证发生在前端表单提交时,第二步验证发生在后台参数注入的时候。
JSR303方式进行的参数校验,官方推荐的实践:hibernate-validator
导入依赖
<dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>6.1.5.Final</version></dependency>
控制器方法中使用javaBean来接收请求参数,在javaBean的成员变量上使用对应的注解,来对注入的参数值进行校验。
@Datapublic class User {@NotNull(message = "用户名不能为空")@Length(min = 10,max = 16,message = "用户名长度必须在10-16之间")@Pattern(regexp = "[a-zA-Z]\\w+",message = "用户名不能以数字开头")private String username;@NotNull(message = "密码不能为空")@Length(min = 6,max = 8,message = "长度只能在6-8之间")private String password;@NotNull(message = "邮箱不能为空")@Pattern(regexp= "\\w{1,15}@\\w{1,15}(.\\w{2,3}){1,2}",message = "邮箱格式不正确")private String email;}
控制器中使用@valid注解对参数注入的值进行校验,校验结果保存在bindingResult中,请注意:bindingResult只能紧跟在要校验的对象之后。
@PostMapping@ResponseBodypublic Result register(@Valid User user, BindingResult bindingResult) throws ParameterValidetorException {//判断验证结果中,是否有错误,如果有错误,意味着参数验证没通过if (bindingResult.hasErrors()) {throw new ParameterValidetorException();}System.out.println(user);return new Result(true, StatusCode.OK,"注册成功",null);}
拦截器
拦截器是springmvc中一个强大的控件,它的功能有点类似于过滤器。拦截器的作用时期是在前端控制器(dispatcherservlet)和被@Controller注解的控制器之间。

在springmvc中,如果要创建拦截器,需要实现一个接口:handlerInterceptor。实现业务时,主要关注:preHandle(),此方法决定是请求是否能向下一步进入到controller中。
步骤1:创建拦截器
/*** 只要实现了HandlerInterceptor接口,当前类就会是一个拦截器*/public class FirstInterceptor implements HandlerInterceptor {/*** 前置处理:在业务控制器方法执行之前执行的* 根据preHandle方法的返回值,决定是否放行 true 放行 false 拦截* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("FirstInterceptor的preHandle执行了");//放行return true;}/*** 后置处理:在控制器方法执行之后再执行的* @param request* @param response* @param handler* @param modelAndView* @throws Exception*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("FirstInterceptor的postHandle执行了");}/*** 渲染视图完成之后执行的* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("FirstInterceptor的afterCompletion执行了");}}
步骤2:配置拦截器
<!--开启拦截器配置--><mvc:interceptors><!--配置某个拦截器,该配置可以有多个--><mvc:interceptor><!--mvc:mapping:用于配置被拦截器拦截的请求资源 黑名单 --><mvc:mapping path="/**"/><!--mvc:exclude-mapping:用于配置不被拦截器拦截的请求资源 白名单 --><mvc:exclude-mapping path="/"/><mvc:exclude-mapping path="/user/login"/><mvc:exclude-mapping path="/user/register"/><mvc:exclude-mapping path="/html/login.html"/><mvc:exclude-mapping path="/html/register.html"/><mvc:exclude-mapping path="/css/*"/><mvc:exclude-mapping path="/js/*"/><mvc:exclude-mapping path="/images/*"/><!--配置使用哪个拦截器来处理被拦截的资源--><bean class="com.woniuxy.interceptor.FirstInterceptor"/></mvc:interceptor></mvc:interceptors>
拦截器链的执行顺序由配置文件中的拦截器配置顺序来决定。
拦截器应用 登录验证
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//登录验证//判断session中是保存了登录状态Object loginUser = request.getSession().getAttribute("loginUser");if (ObjectUtils.isEmpty(loginUser)) {response.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");response.getWriter().write("当前用户尚未登录");//拦截return false;}return true;}}
<!--开启拦截器配置--><mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><mvc:exclude-mapping path="/"/><mvc:exclude-mapping path="/user/login"/><mvc:exclude-mapping path="/user/register"/><mvc:exclude-mapping path="/html/login.html"/><mvc:exclude-mapping path="/html/register.html"/><mvc:exclude-mapping path="/css/*"/><mvc:exclude-mapping path="/js/*"/><mvc:exclude-mapping path="/images/*"/><bean class="com.woniuxy.interceptor.LoginInterceptor"/></mvc:interceptor></mvc:interceptors>
ssm整合 (spring springmvc mybatis)
整合时如果不考虑父子容器的问题,就一定导致一个后果:声明式事务失效。
父子容器
让spring扫描service
让springmvc扫描controller
整合实现
spring整合mybatis
与之前的配置一样。
spring整合springmvc
1、web.xml配置,让web容器启动时先创建父容器,后创建子容器。
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><!--加载类路径下的xml文件创建父容器--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><!--监听servletContext对象的创建--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 创建dispatcherservlet时,创建子容器 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
2、配置spring和springmvc各自扫描的包
让spring扫描service
<context:component-scan base-package="com.woniuxy.service"/>
让springmvc扫描controller
<context:component-scan base-package="com.woniuxy.controller"/>
此时整合即已完成。
SSM整合及声明式事务:
applicationContext.xml spring配置
<?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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://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"><context:component-scan base-package="com.woniuxy.service"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql:///bank?characterEncoding=utf-8&useSSL=false"/><property name="username" value="root"/><property name="password" value="root"/></bean><!--配置sqlSessionFactoryBean作用:产生一个sqlsessionfactory 只要ioc容器中有任何一个bean需要使用sqlsession,那么就会由sqlsessionfactory自动创建一个给其使用。--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><!-- <property name="configLocation" value="classpath:sqlConfig.xml"/>--></bean><!--配置MapperScannerConfigurer:作用:用于扫描指定的包,创建对应接口的代理对象--><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.woniuxy.mapper"/></bean><!--配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 对声明式事务的注解提供支持 --><tx:annotation-driven/></beans>
springmvc.xml springmvc配置
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="com.woniuxy.controller"/><mvc:annotation-driven/><!-- <mvc:resources mapping="/js/**" location="/js/"/>--><mvc:resources mapping="/html/**" location="/html/"/></beans>
数据访问层
public interface AccountMapper {@Select("select * from account where username=#{username}")Account findByUserName(String username);@Update("update account set balance=#{balance} where username=#{username}")int updateAccount(Account account);}
业务层
@Service("accountService")@Transactionalpublic class AccountServiceImpl implements AccountService {@Resourceprivate AccountMapper accountMapper;@Overridepublic void transfer(TransferVo transferVo){//查询要进行转帐操作的两个人的帐户信息Account sourceAccount = accountMapper.findByUserName(transferVo.getSource());Account targetAccount = accountMapper.findByUserName(transferVo.getTarget());//判断被转出人的帐户余额是否足够if (sourceAccount.getBalance()>transferVo.getMoney()) {//真正执行转账操作sourceAccount.setBalance(sourceAccount.getBalance()-transferVo.getMoney());targetAccount.setBalance(targetAccount.getBalance()+transferVo.getMoney());accountMapper.updateAccount(sourceAccount);System.out.println(1/0);accountMapper.updateAccount(targetAccount);}}}
控制层
@Controllerpublic class AccountController {@Resourceprivate AccountService accountService;@RequestMapping("account/transfer")@ResponseBodypublic Result transfer(TransferVo transferVo){accountService.transfer(transferVo);return new Result(true, StatusCode.OK,"转账成功",null);}}
