美文网首页
Spring+SpringMVC+事务的demo

Spring+SpringMVC+事务的demo

作者: 油麦 | 来源:发表于2018-02-28 16:00 被阅读37次

    1.实例概述

    对Spring技术既陌生又熟悉,常听闻SpringMVC技术的优秀,从而将Spring等同于SpringMVC,其实Spring是一个很大的生态,SpringMVC仅仅是一个子项目。
    持久层的“Spring JDBC”的, 业务层的“声明式事务”, 和展现层的“Spring MVC”。 这几个原生的技术就能实现一个简单的Web应用

    实例简介:

    一个普通的登入模块,登入时增加积分,然后后台需要做日志记录

    开发分析:

    1.首先是考虑数据库的设计,这里使用两张表,分别记录用户信息和登入日志。
    2.然后考虑DAO层的设计,这里是对两张表进行操作,所以对应两个DAO类。
    3.再者Services的设计,登入操作是一个业务逻辑只对应一个Services,其中具体的逻辑再分别调用两个DAO进行持久化
    4.最后是展现层的设计,在本例中,有登录页和欢迎页,在登录页输入帐号和密码,匹配成功后跳转到欢迎页且显示登录名。登入失败重定向到登入页。

    开发的准备

    数据库的创建: 注意引擎为 ENGINE=InnoDB,这个支持事务,默认的是MyISAM,不支持事务,但是读写比较快
    这里学学习在DOS命令下运行脚本,在脚本环境该开始经常混淆的是文件地址的编写 不同系统的路径
    项目工程的创建: 首先对工程的编码格式统一为UTF-8
    在pom.xml文件中配置Spring,数据源和数据库连接驱动,Servlet类库的依赖信息
    规划Spring的配置文件
    类包的规划:domain(领域对象)严格是属于业务层,但是领域对象可能同时被持久成和展现层共享,所以一般单独划分为一个包。
    测试类和程序的类包一样,但是放在不同的物理位置,方便以后部署时打包
    spring的配置文件规划:spring可以将所有的配置信息放到同一个文件夹也可以分开,根据项目的大小决定。

    2. 代码开发

    领域对象domain/entity

    实体类,代表了业务的状态并被实体化到数据库中,领域对象不一定等同于数据库表,在mybatis中,领域对象的属性和数据库表的字段不一定一一对应。
    针对需求,设置两个实体类,对应用户信息的User.java和对应登录日志的LoginLog.java

    2.1 持久层DAO

    2.1.1 DAO层类和方法的设计

    首先需要明白DAO层的意义,DAO层简单的说就是调用数据库,对数据库进行增删改查,而往往删除是用“改”来操作的。一个DAO层往往都是根据实体去分的,和用户有关的一个DAO类之类的。然后DAO里面包括多个方法,一个方法就是一次具体的增删改查的操作。而DAO是给Service调用的,一次Service往往包括多个DAO,像一次“登入”就包括积分,登入ip,账户匹配等多个DAO方法。
    负责数据的访问和操作,被业务层调用。将数据表中加载的数据实例化为领域对象,将领域对象持久化到数据表中。(持久化的全称:一些专业名次往往只有动词,尝试补充完整的主宾能加深理解)
    DAO层的操作就是如下几种,这里我们考虑的是dao层方法的设计!注意和API设计分开:

    1. 增:
      dao层方法的插入,往往是接收一个对象参数,然后将对象里面的属性取出来,再调用API,执行sql语句和赋参
    update(String sql, Object... args)
    
    1. 改:
      改变数据肯定也需要先找到那条数据然后再进行改动吧,所以方法签名也一定会有字符串的条件。
    2. 查:
      查就是比较常用的操作,分为两种查询方式吧。一种是带操作的查,一种是仅仅看是否存在的查。但是查找一定都是根据条件的查,所以方法签名一定有条件的。
    3. 返回一个对象的查
      数据库API的操作结果是一个结果集,怎么把这个集合的元素转换为对象集或者对象输出呢。这是要好好使用API考虑的地方
      使用jdbcTemplate:
    void query(String sql, Object[] args, RowCallbackHandler rch)
    
    1. 返回一个表示查询结果的值
      service层传入几个参数,然后DAO调用数据库,将这几个参数变为数据库一条数据,返回的一个判断是否成功的值(boolean,或者数字)

    2.2.2 在spring中装配DAO

    原因(意义):
    在DAO层类中都只有sql的执行语句(也就是涉及业务的部分),只是调用jdbcTemplate,那么现在就应该解决数据库的打开和连接操作。
    做法思路:
    jdbcTemplate里面包含数据库连接的样板操作,所以需要配置一个DataSource,这样就能从数据源中获取连接。具体的操作如下:

    1. 声明一个数据源
    2. 定义一个jdbcTemplate Bean
    3. 通过Spring的上下文绑定记着进行Bean的注入

    2.2.2.1 声明一个数据源

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close" 
            p:driverClassName="com.mysql.jdbc.Driver"
            p:url="jdbc:mysql://localhost:3306/sampledb"
            p:username="root"
            p:password="admin" />
    

    2.2.2.2 定义一个jdbcTemplate Bean

    <!-- 配置Jdbc模板  -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
            p:dataSource-ref="dataSource" />
    

    2.2.2.3 通过Spring的上下文绑定记着进行Bean的注入

    声明一个jdbcTemplate的变量
    注解@Autowired生成一个,jdbcTemplate的setter方法
    

    2.2 业务层Service

    Service层需要在类上注解@Service

    2.2.1 业务层的实现

    思路介绍:
    业务层就是实现一次操作,可以抽象认为是用户的一次点击,往往涉及到多个Dao方法的操作,这时候要加上事务的注解。

    @Service
    public class UserService {
        private UserDao userDao;
        private LoginLogDao loginLogDao;
    
        @Autowired
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
        // 这就是IoC的属性注入的方式,当被调用时才会使用
        @Autowired
        public void setLoginLogDao(LoginLogDao loginLogDao) {
            this.loginLogDao = loginLogDao;
        }
    
        /**
         * 登入匹配,调用Dao中方法查询是否数据库中存在这个值
         * @param userName
         * @param password
         * @return
         */
        public boolean hasMatchUser(String userName,String password){
            int matchCout = userDao.getMatchCount(userName,password);
            return matchCout > 0;
        }
    
        /**
         * 通过用户名查询实体
         * @param userName
         * @return
         */
        public User findUserByUserName(String userName){
            User user = userDao.findUserByUserName(userName);
            return user;
        }
    
        /**
         * 这是登入成功时调用的方法
         * @param user
         */
        @Transactional
        public void loginSuccess(User user){
            user.setCredits(5 + user.getCredits());
            LoginLog loginLog = new LoginLog();
            loginLog.setIp(user.getLastIp());
            loginLog.setUserId(user.getUserId());
            loginLog.setLoginDate(user.getLastVisit());
            userDao.updateLoginInfo(user);
            loginLogDao.insertLoginLog(loginLog);
        }
    
    }
    

    2.2.2 装配业务层

    原因(意义):
    事务管理的代码虽然没出现在程序中(程序中我们只是在一个方法中调用多个dao方法,然后在方法上添加一个@Transaction)。但是必须告诉spring那些业务需要工作在事务环境下、以及食物的规则等。这样spring才能实现事务管理的功能。
    做法思路:

    1. 添加aop和tx命名空间的Schema定义文件,这样才能使用配置标签
    2. 添加包到上下文扫描路径中,这样注解才能生效
    3. 配置事务管理器
    4. 增加事务增强
      实现:
    5. 添加aop和tx命名空间的Schema定义文件,这样才能使用配置标签
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xmlns:tx="http://www.springframework.org/schema/tx"
    
    1. 添加包到上下文扫描路径中,这样注解才能生效
    
    
    1. 配置事务管理器,基于数据源,需要引用
    <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
    p:dataSource-ref="dataSource" />
    
    1. 增加事务增强,使她们都工作在事务环境中
    <aop:config proxy-target-class="true">
            <aop:pointcut id="serviceMethod"
                expression="(execution(* com.smart.service..*(..))) and (@annotation(org.springframework.transaction.annotation.Transactional))" />
            <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="*" />
            </tx:attributes>
    </tx:advice>
    

    2.3 展现层View(Web)

    2.3.1 配置spring MVC框架

    1. 通过web容器的上下文参数指定配置spring配置文件的地址
    2. 指定web容器的监听器,该监听器在web容器启动时自动运行,加载spring的配置文件,然后启动spring容器
    3. 在web.xml配置一个Servlet拦截url请求
    4. 最后需要配置spring mvc相关的信息
      具体:
    5. 对web.xml文件进行配置````

      <context-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>classpath:mymaster-context.xml</param-value>
      </context-param>
    2. 指定web容器的监听器,该监听器在web容器启动时自动运行,加载spring的配置文件,然后启动spring容器
    


    <listener>

    <listener-class>
    org.springframework.web.context.ContextLoaderListener
    </listener-class>
    </listener>

    3. 在web.xml配置一个Servlet拦截url请求
    

    <servlet>
    <servlet-name>smart</servlet-name>
    <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>3</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>smart</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    
    Servlet有一个契约,就是servlet名字-servlet.xml的配置文件,且这个不用想spring容器的配置文件那样上下文参数声明contextConfigLocation
    4. 最后需要配置spring mvc相关的信息
    ###2.3.2 处理登入请求
    ####2.3.2.1 pojo控制器类
    ####2.3.2.2 SpringMVC配置文件
    ####2.3.2.3 ModelAndView的解析配置
    
    ###2.3.3 JSP视图页面
    
    ####2.3.3.1 登入页
    
    ####2.3.3.2 欢迎页
    
    ##2.4 运行Web应用
    
    
    问题:
    springon容器是如何启动的?
    通过配置文件启动的,项目中是通过web容器读取配置文件启动spring容器,测试是直接读取配置文件
    配置文件有哪些?
    web.xml:这是配置web容器的
    servletname-servlet.xml: 这是配置spring的扫描包和视图解析器
    spring-context:这是配置spring容器
    pom.xml:配置依赖的模块

    相关文章

      网友评论

          本文标题:Spring+SpringMVC+事务的demo

          本文链接:https://www.haomeiwen.com/subject/dytixftx.html