[手把手教程][JavaWeb]SSM框架验证、修复和实例

[手把手教程][JavaWeb]SSM框架验证、修复和实例

手把手验证上期的SSM项目:优雅的SpringMvc+Mybatis整合之路框架。

  • 说实话,这一期也应该算是上一期的,但是这起需要单独拿出来的原因有几个,最重要的是我个人讨厌长篇大论。(最简单的就是直接丢项目)
  • 但是,直接丢出来,未免太过粗糙,也不能体验出我们编程的思维养成,故此一步一步的走出来。
  • 对于很多哥们催更的事情,这个确实也不是那么容易出来的,前面的框架搭建是从网上找的资料一步一步的组合的,但是实际使用还是有很多问题,本篇文章将会解决这些问题。
  • 同时,兄弟们稍微耐心点,我这边也是一点点实现,还请客官们放下手中的西瓜刀。
  • 再次安利一波,博客地址:acheng1314.cn

工具

  • IDE为idea15
  • JDK环境为1.8
  • maven版本为maven3
  • Mysql版本为5.5.27
  • Tomcat版本为7.0.52

本期目标

  • 项目框架介绍和冲突解决
  • 实例Service和Dao。项目框架测试。
  • 登录、注册业务的分析、创建和演示

冲突解决

为什么我把冲突解决放在第一位?

因为在冲突解决后,我们可以进入测试阶段,同时在解决冲突的时候,我们会一点点的体会到SSM项目框架中各个框架之间是怎么协同工作的,也就可以完成项目介绍。

重要的是,在实际生活中,我们去公司上班,一般也是先解决项目框架冲突问题。

  • 打开项目后,随意选择一个Spring的配置文件,会弹出如下界面:

    ssm框架检测第一步
    ssm框架检测第一步

    我们点击图中右上角圈出来部分,会弹出如下界面:

    ssm框架检测第二步
    ssm框架检测第二步

    这里我们什么都不需要做,直接点击OK

    上面两步是为了告诉Idea我们的Spring配置文件在哪。类似单一Spring配置文件的ApplicationContext.xml一样,我们只是将Spring根据模块分发而已。

  • 在Tomcat中运行本项目,运行结果应该是在浏览器中显示Hello World界面。

    • 配置Tomcat

    • 配置项目的Tomcat启动设置。

    • 参考连接:点击进入

    • 在web浏览器中输入:localhost:8080/druid ,查看druid是否配置成功。

      ssm框架检测第三步
      ssm框架检测第三步

      如上面的图中,我们可以看到我们的druid并没有把JDBC驱动列出来。这说明我们的项目的JDBC驱动要么没有设置,要么是数据库驱动的配置文件没做好。

    • 随意输入一个localhost:8080/下的地址,至此我们要展示错误404页面。并且把Tomcat不友好的404页面替换。

      • 替换思路:错误404这种常出现的页面,我们可以设置为静态资源,以加快网页访问。

      • 注意:我们需要先把WEB-IN\Fweb.xml下面的mvc-dispatcher更改为全局配置。

        <servlet-mapping>
            <servlet-name>mvc-dispatcher</servlet-name>
            <!-- 默认匹配所有的请求 -->
            <!-- 我们默认配置这个是为了让我们的Spring框架接管Servelt,实现Spring控制所有站点请求 -->
            <url-pattern>/</url-pattern>
            <!--<url-pattern>/css/*</url-pattern>-->
            <!--<url-pattern>/images/*</url-pattern>-->
            <!--<url-pattern>/fonts/*</url-pattern>-->
        </servlet-mapping>
        

        配置了web.xml后,我们重启重启应用,输入一个错误的地址(跳转到404页面),会发现提示错误信息,主要报错如下

         Exception encountered during context initialization - cancelling refresh attempt: 
            org.springframework.beans.factory.BeanCreationException: 
                Error creating bean with name 'dataSource' defined in file [项目所在的物理地址\WEB-INF\classes\spring\spring-dao.xml]: 
                    Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/slf4j/Logger
            
            //上面这个错误主要是提示我们:NoClassDefFoundError: org/slf4j/这个类找不到。
        
        解决办法:偷懒的把log4j2从maven配置文件中删除了,开启了logback,在maven的pom.xml中:
            
            <!-- 1.日志 -->
            <!--<!– 实现slf4j接口并整合 –>-->
            <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.1</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${org.slf4j.version}</version>
            </dependency>
        
            <!--log4j2支持-->
            <!--<dependency>-->
                <!--<groupId>org.apache.logging.log4j</groupId>-->
                <!--<artifactId>log4j-core</artifactId>-->
                <!--<version>${org.apache.logging.log4j.version}</version>-->
            <!--</dependency>-->
            <!--<dependency>-->
                <!--<groupId>org.apache.logging.log4j</groupId>-->
                <!--<artifactId>log4j-api</artifactId>-->
                <!--<version>${org.apache.logging.log4j.version}</version>-->
            <!--</dependency>-->
        

        接着,我们重启Tomcat,等项目部署完成后,我们再次打开,再次输入错误地址,我们发现还是在报错,信息如下:

        Exception encountered during context initialization - cancelling refresh attempt: 
            org.springframework.beans.factory.BeanCreationException: 
                Error creating bean with name 'sqlSessionFactory' defined in file [项目物理地址\WEB-INF\classes\spring\spring-dao.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: 
                    Failed to convert property value of type [java.lang.String] to required type [org.springframework.core.io.Resource[]] for property 'mapperLocations'; 
                        nested exception is java.lang.IllegalArgumentException: 
                            Could not resolve resource location pattern [classpath:mapper/*.xml]: class path resource [mapper/] cannot be resolved to URL because it does not exist
                            
            根据上面的提示信息,我们可以看到提示的是mapper下面没有文件,那么我们就给他制定一个空的配置文件(BaseDao.xml),内容如下:
            
                <?xml version="1.0" encoding="UTF-8" ?>
                <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
                <!-- namespace是指明Mybatis扫描的目录,mapper是我们的Dao层的映射目录 -->
                <mapper namespace="cn.acheng1314.dao">
                </mapper>
        

        同样的,我们再次重启服务器,并且输入错误的地址,现在能正常显示错误404的页面了,但是页面太过Low了,我们得重写一下web.xml的配置。404页面如下所示:

        ssm框架检测404模版页面
        ssm框架检测404模版页面

        解决思路:错误404的页面是常用页面之一,所以我们在项目的资源目录(webapp)下创建一个static目录,专门用来存放静态资源,如js、css、错误提示页面、登录、注册页面等等。

        通过网上查阅资料,我们看到大部分人都是把404页面提示信息提交给Servelt自己管理,我们也依样画瓢,在web.xml中配置,如下:
        <error-page>
            <error-code>404</error-code>
            <Location>/static/view/404.html</Location>
        </error-page>
        

        同时,我们需要给Spring写一个web的配置,控制哪些资源被拦截。spring-web.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-3.0.xsd">
            <!-- 配置SpringMVC -->
            <!-- 1.开启SpringMVC注解模式 -->
            <!-- 简化配置:
                (1)自动注册DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter
                (2)提供一些列:数据绑定,数字和日期的format @NumberFormat, @DateTimeFormat, xml,json默认读写支持
            -->
            <mvc:annotation-driven/>
            <!-- 2.静态资源默认servlet配置
                (1)加入对静态资源的处理:js,gif,png
                (2)允许使用"/"做整体映射
             -->
            <mvc:resources mapping="/css/**" location="/static/css/" />
            <mvc:resources mapping="/images/**" location="/static/images/" />
            <mvc:resources mapping="/view/**" location="/static/view/" />
            <mvc:default-servlet-handler/>
        
            <!-- 3.配置jsp 显示ViewResolver -->
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
                <property name="prefix" value="/WEB-INF/jsp/"/>
                <property name="suffix" value=".jsp"/>
            </bean>
        
            <!-- 4.扫描web相关的bean配置 -->
            <context:component-scan base-package="cn.acheng1314.mvc">
                <!-- 制定扫包规则 ,只扫描使用@Controller注解的JAVA类 -->
                <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            </context:component-scan>
        
        </beans>
        

        以上文件配置好后,我们重启服务器,并输入错误地址,现在我们插入的404页面正常显示了。

        通过上面的资料,我们可以大胆整理下web请求的思路:

        用户发起请求→DNS解析发现服务器→建立链接发送请求→WEB服务器分发给应用服务器→MVC层框架处理请求过程→返回数据给用户

        而上面的SpringMvc作为框架层,我们也可以通过网上资料和我们目前的配置做出一些构想:

        Tomact分发请求→Servelt收到请求→Spring接管Servelt→DispatcherServlet处理请求分发→根据Spring配置找到对应的控制器(Controller)处理业务→返回对应数据。

        而下面有一张更加突出的图片说明了这一切:

        SpringMVC详细运行流程图

        总结:目前项目中的静态资源我们已经处理完毕,加入了一部分Web的静态资源增加了Spring的web处理配置修改了web.xml,log4j2替换为LogBack,Junit版本提升为4.12,加入了一个BaseMapper.xml

        web.xml文件如下:

        <!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 xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
          <welcome-file-list>
              <welcome-file>index.html</welcome-file>
              <welcome-file>index.htm</welcome-file>
              <welcome-file>index.jsp</welcome-file>
              <welcome-file>default.html</welcome-file>
              <welcome-file>default.htm</welcome-file>
              <welcome-file>default.jsp</welcome-file>
          </welcome-file-list>
          <!-- 如果是用mvn命令生成的xml,需要修改servlet版本为3.1 -->
          <!-- 配置DispatcherServlet -->
          <servlet>
              <display-name>SSM</display-name>
              <servlet-name>mvc-dispatcher</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!-- 配置springMVC需要加载的配置文件
                  spring-dao.xml,spring-service.xml,spring-web.xml
                  Mybatis - > spring -> springmvc
               -->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:spring/spring-*.xml</param-value>
              </init-param>
          </servlet>
          <servlet-mapping>
              <servlet-name>mvc-dispatcher</servlet-name>
              <!-- 默认匹配所有的请求 -->
              <url-pattern>/</url-pattern>
              <!--<url-pattern>/css/*</url-pattern>-->
              <!--<url-pattern>/images/*</url-pattern>-->
              <!--<url-pattern>/fonts/*</url-pattern>-->
          </servlet-mapping>
        
          <!-- spring框架提供的字符集过滤器 -->
          <!-- spring Web MVC框架提供了org.springframework.web.filter.CharacterEncodingFilter用于解决POST方式造成的中文乱码问题  -->
          <filter>
              <filter-name>encodingFilter</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>
              <!-- force强制,促使 -->
              <init-param>
                  <param-name>forceEncoding</param-name>
                  <param-value>true</param-value>
              </init-param>
          </filter>
          <filter-mapping>
              <filter-name>encodingFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
        
          <!--druid ==> WEB方式监控配置-->
          <servlet>
              <servlet-name>DruidStatView</servlet-name>
              <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>DruidStatView</servlet-name>
              <url-pattern>/druid/*</url-pattern>
          </servlet-mapping>
          <filter>
              <filter-name>druidWebStatFilter</filter-name>
              <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
              <init-param>
                  <param-name>exclusions</param-name>
                  <param-value>/public/*,*.js,*.css,/druid*,*.jsp,*.swf</param-value>
              </init-param>
              <init-param>
                  <param-name>principalSessionName</param-name>
                  <param-value>sessionInfo</param-value>
              </init-param>
              <init-param>
                  <param-name>profileEnable</param-name>
                  <param-value>true</param-value>
              </init-param>
          </filter>
          <filter-mapping>
              <filter-name>druidWebStatFilter</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>
        
          <error-page>
              <error-code>404</error-code>
              <location>/static/view/404.html</location>
          </error-page>
        </web-app>
        

        BaseMapper.xml如下:

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
              <!-- namespace指向我们的dao所在的地址 -->
        <mapper namespace="cn.acheng1314.dao">
        </mapper>
        

        其他的文件修改的信息都可以在上面看到就不再次贴出来了。

SSM框架实例--仓库管理系统--登录注册的功能分析

分析:

  • 登录和注册,都是用户的行为,也是我们开发中常说的某个行为对应的业务
  • 注册用户,意味着添加用户,添加了用户后,我们才有登录功能的继续执行的可能。
  • 用户登录,也是用户信息的查找和比对过程。一般来说用户先把信息提交给程序,然后程序按照流程执行后提交数据给服务器这个流程中程序可能会产生一些业务逻辑的判断),服务器收到数据并进行数据对比,当用户信息存在且帐号和密码匹配才能登录成功,否则前面的任意条件不满足即为登录失败
  • 我们可以依靠单一的用户表来实现用户的登录数据获取注册信息的添加

功能大概分析完毕后,我们就可以考虑下如何实现这些功能。大概图示如下:

ssm框架经典三层分析
ssm框架经典三层分析
  • 首先用户信息需要存储,我们需要数据库的支撑。
  • 有了数据库的支援后,我们需要先测试用户信息的添加和查找。就是我们常说的Dao层。
  • 当我们的Dao层拿到想要的数据,我们需要Service层将Dao层的操作作为服务提供给控制器,再由控制器提供给前台页面。
  • 同样的用户需要获取某个数据,先是浏览器获取到用户请求→web层→Service层→Dao层,再接着重复上面的操作。

上面一张图用模型已经很好的说明了java web后端各层的关系,下面一张图是经典三层对照MVC的描述。

ssm框架经典三层分析对照Mvc
ssm框架经典三层分析对照Mvc

上面的图引用自互联网资料,下面的黑色字是我添加上去的。

  • 上面图中,我们可以看到一部分MVC设计和图中标记的类似,但是这只是一种MVC模式的栗子。

  • 关于更加详细的MVC,我们可以百度百科查看。


上面提到的东西,我们适可而止就行了,很多东西现在还不是深究的时候,我们要先懂一个事物的外在表现,才有进一步的探索,所以我们需要等缘分的到来。

SSM框架实例--仓库管理系统--注册、登录的功能模拟实现

按照前面我们的分析来讲,我们需要先考虑Dao层的实现,毕竟有了Dao层对数据的封装,才可以有后面的操作,所以后面我的栗子中,一切都是按照Dao→Service→Controller→View这样的一个步骤来实现。

  • 用户注册功能的Dao层实现。
    • 数据库基本操作为:增删改查。

    • 我们根据数据库常规操作的类型,分别对其进行抽象,所以产生了Dao.java这个接口对象的基本模型。代码如下:

      /**
       * 通过接口编程
       * @param <T> 泛型用于解耦,同时避免写重复代码
       */
      public interface Dao<T> {
          /**
           * 添加某个对象
           * @param t 待添加的对象
           * @return  返回受影响的行数
           */
          int add(T t);
      
          /**
           * 删除某个对象,在企业开发中,我们一般不做物理删除,只是添加某个字段对其数据进行可用控制
           * @param t 待删除对象
           * @return 返回受影响的条数
           */
          int  del(T t);
      
          /**
           * 更新某个对象
           * @param t 待更新对象
           * @return 返回受影响的条数
           */
          int update(T t);
      
          /**
           * 通过ID查找一个对象
           * @param Id    待查询的对象的ID
           * @return  返回该ID对应的对象
           */
          T findOneById(Serializable Id);
      
          /**
           * 查找对象集合
           * @return  返回对象集合
           */
          List<T> findAll();
      }
      
    • 实现用户的Dao层:

      • 我们要针对用户写用户的Dao层,我们需要有一个用户对象的封装,直接在domain包下面创建User.java,代码如下:
      /***
      创建数据库用户表:
       CREATE TABLE `user` (
       `login_id` varchar(20) NOT NULL COMMENT '登陆ID',
       `pwd` varchar(20) NOT NULL COMMENT '用户密码',
       `name` varchar(100) NOT NULL COMMENT '用户姓名',
       `age` int(3) NOT NULL COMMENT '用户年龄',
       `sex` varchar(3) NOT NULL COMMENT '性别',
       `duty` varchar(15) COMMENT '职务',
       `cell_number` varchar(15) COMMENT '手机号',
       `photo_url` varchar(75) COMMENT '头像地址',
       `used` boolean NOT NULL COMMENT '账号是否可用',
       PRIMARY KEY (`login_id`)
       ) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='用户表';
      
       插入默认数据:
       INSERT INTO `user` (`login_id`,`pwd`,`name`,`age`,`sex`,`used`)
       VALUES
       ('pc859107393','123456','阿程',20,'男',true),
       ('pc228568859','123456','chengcheng',20,'女',true),
       ('pangpang','123456','余下一整夜',25,'男',true),
       ('111111','123456','手拉手系列教程',22,'女',true);
       */
      
      public class User implements Serializable {
          private String name;    //名字
          private String sex; //性别
          private String loginId; //登陆ID
          private String pwd;    //密码
          private String duty;    //职务
          private int age;    //年龄
          private String cellNumber;  //手机号
          private String photoUrl;    //头像地址
          private boolean used = true;   //是否可用,默认值是true
          
          ···省略get、set和toString
      }    
      
      //推荐大家把每个bean对应的数据库操作备注到上面。
      //打开Navicat For Mysql,链接上数据库,创建对应的数据库,并运行上面的sql产生数据库表和初始记录。
      
      • 当我们数据库创建完毕后,我们需要写一个接口对user表进行操作封装。我们在dao包下面创建UserDao接口,代码如下:
      /**
       * 在传统的jdbc操作中,我们需要手动管理数据库连接的开关,数据库资源访问的开关等等
       * <br/>但是,我们这里采用了Mybatis和Druid这两个框架,那么我们可以完全不必理会数据库连接等等的控制,
       * <br/>我们只需要更加专注于业务实现的开发。
       */
      public interface UserDao extends Dao<User> {
          int add(User user);
      
          int del(User user);
      
          int update(User user);
      
          User findOneById(Serializable Id);
      
          List<User> findAll();
      }
      
      
      • 完成UserDao的封装后,传统的操作这一步需要自己手动实现UserDao的Impl,并实现对数据库的操作等等。而我们使用Mybatis后,UserDao的Impl在Mybatis的mapper文件夹中指定为xml,我们的Dao文件除了数据库操作的语句其他的都无需关注,那么剩下的数据库操作什么的我们都无需关心,毕竟Mybatis和druid都把其他的事情帮我们做了。UserDao.xml如下:
      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <!-- namespace指定我们的到具体的bean -->
      <mapper namespace="cn.acheng1314.dao.UserDao">
      
          <!--查找-->
          <select id="findOneById" resultType="User" parameterType="String">
              SELECT
              *
              FROM
              `user`
              WHERE
              login_id = #{userId}
          <select>
      
          <!--增加语句-->
          <insert id="add" parameterType="User">
          INSERT INTO
              `user`
              (`login_id`,`name`,`age`,`sex`,`duty`,`cell_number`,`photo_url`,`pwd`,`used`)
              VALUES
              (#{loginId},#{name},#{age},#{sex},#{duty},#{cellNumber},#{photoUrl},#{pwd},#{used})
          </insert>
      
          <!-- 删除 -->
          <update id="del" parameterType="User">
              UPDATE
              `user`
              SET
              `used`=FALSE
              WHERE
              `login_id`=#{loginId};
          </update>
      
          <!-- 更新用户信息 -->
          <update id="update" parameterType="User">
              UPDATE
              `user`
              SET
              `name`=#{name}, `age`=#{age}, `sex`=#{sex}, `duty`=#{duty}, `cell_number`=#{cellNumber}, `photo_url`=#{photoUrl}
              WHERE
              `login_id`=#{loginId};
          </update>
      </mapper>
      
      • mapper下面的UserDao.xml已经完成,这就意味着我们的UserDao基本完成,那么我们应该来一次单元测试来看看效果如何。UserDaoTest.java如下:
      @RunWith(SpringJUnit4ClassRunner.class) //spring的单元测试
      @ContextConfiguration({"classpath:spring/spring-*.xml"})    //上下文配置
      public class UserDaoTest {
      
          @Autowired
          private UserDao userDao;    //初始化Dao层,面向接口编程
          
          /**
          * 添加用户的单元测试,添加成功与否会有对应的提示。
          * 当然按照我这个配置一般会正确,如果说出错就需要你一步一步的看错误的提示代码了。
          * 添加同样的LoginId的用户会添加失败,因为在上面把LoginId作为了数据库表的主键。
          */
          @Test
          public void testAdd() {
              User user = new User();
              user.setLoginId("pc147852369");
              user.setName("雨下一整夜");
              user.setPwd("123456");
              user.setSex("未知");
              int result = 0; //受影响的行数默认为0
              try {
                  result = userDao.add(user);
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("添加用户失败");
              }
              if (result>0)
                  System.out.println("添加用户成功");
          }
          
          /**
          * 查找用户测试,成功与否会有log输出
          */
          @Test
          public void testFindOneId() throws Exception {
              User user = new User();
              user.setLoginId("pc147852369");
              User result = null; //受影响的行数默认为0
              try {
                  result = userDao.findOneById(user.getLoginId());
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("查找用户失败");
              }
              if (null!=result)
                  System.out.println("查找用户成功\n"+result.toString());
          }
      
          @Test
          public void testDel() {
              User user = new User();
              user.setLoginId("pc147852369");
              int result = 0; //受影响的行数默认为0
              try {
                  result = userDao.del(user);
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("删除用户失败");
              }
              if (result>0)
                  System.out.println("删除用户成功");
          }
      
          @Test
          public void testUpdate() {
              User user = new User();
              user.setLoginId("pc147852369");
              user.setName("手把手教程");
              user.setPwd("123456");
              user.setSex("男");
              int result = 0; //受影响的行数默认为0
              try {
                  result = userDao.update(user);
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("更新用户信息用户失败");
              }
              if (result>0)
                  System.out.println("更新用户信息用户成功");
      
          }
      }
      

      数据的操作结果我们都可以在mysql中查看,这里就不一一截图了。当然我们也可看到每次单元测试都需要在类上面注解spring单元测试和spring的上下文,按照我们编程的原则,一次编码处处运行,我们可以把这些注解放到BaseTest.java中,后面所有的单元测试都继承BaseTest.java即可避免大量重复编码

    • UserService实现(注意编程思维的养成)

      • 根据我们面向接口编程的思维来讲,我们在Service中核心是实现Dao层,并调用Dao层。
      • 刚才我们单元测试,我们的UserDao层通过测试了,我们现在中心就应该放在业务逻辑的实现,而不是继续纠缠Dao层,毕竟数据持久化已经实现了。
      • 从服务端程序的角度看来,用户的主要业务有注册、登录、注销登录、注销帐号等等,这里我们先拿注册来说事。

      • 用户注册流程分析(用户角度):
        • 填写帐号相关信息
        • 提交注册信息
        • 服务器返回是否注册成功
      • 用户注册流程分析(服务器角度):
        • 收到用户注册请求
        • 解包数据→封装到UserBean
          • 解包数据失败(请求信息异常),返回错误提示信息
        • 针对具体的用户信息检查是否符合标准
          • 不符合检查标准,返回对应的错误提示
        • 通过检查,调用Dao检查是否存在同样的用户
          • 数据库已经存在相同的用户信息,不能重复添加,返回错误提示信息
        • 不存在同样的用户,添加新用户,并返回成功的提示信息

      流程图反映如下:

      ssm框架用户行为解析流程图
      ssm框架用户行为解析流程图
      • 代码实现用户注册的Service:
      //创建一个BaseService接口,用泛型解耦
      public interface UserService extends BaseService<User> {
          //添加用户的实例
          void add(User user) throws Exception;
      }
      
      ------------------------------分割线----------------------------------
      
      //创建一个UserService继承BaseService,并指定具体的实体类型
      //为什么要再写一个UserService接口?不同对象的业务体系不同,BaseService并不能完全替代不同对象的具体行为表现
      public interface UserService extends BaseService<User> {
      
          void add(User user) throws Exception;
      }
      
      ------------------------------分割线----------------------------------
      
      //创建UserServiceImpl实现UserService接口
      @Service("userService")
      public class UserServiceImpl implements UserService {
      
          @Autowired
          private UserDao userDao;
      
          /**
           * 添加用户,一般来说需要检查用户为空、用户名为空、密码为空
           */
          public void add(User user) throws UserCanNotBeNullException, UserNameCanNotBeNullException, UserPwdCanNotBeNullException, UserAireadyExistException, OtherThingsException {
              //先检查用户是否存在
              if (null == user) {
                  //抛出用户为空的自定义异常
                  throw new UserCanNotBeNullException("User can not be Null");
              }
              //用户名不能为空检查
              if (StringUtils.isEmpty(user.getLoginId())) {
                  //抛出用户名为空的自定义异常
                  throw new UserNameCanNotBeNullException("User name can not be Null");
              }
              //用户密码不能为空检查
              if (StringUtils.isEmpty(user.getPwd())) {
                  //抛出用户密码为空的自定义异常
                  throw new UserPwdCanNotBeNullException("User name can not be Null");
              }
              //由于我这个是仓库管理系统,根据业务需求来说,我们的用户基本信息都是不能为空的
              //基本信息包括:姓名、年龄、用户名、密码、性别、手机号,年龄大于18
              if (StringUtils.isEmpty(user.getDuty())
                      || StringUtils.isEmpty(user.getSex())
                      || user.getAge() > 18
                      || StringUtils.isEmpty(user.getCellNumber())) {
                  //其他综合异常
                  throw new OtherThingsException("Some use's base info can not be null");
              }
              //已经存在相同用户
              if (null != userDao.findOneById(user.getLoginId())) {
                  //存在相同的用户异常
                  throw new UserAireadyExistException("Register User Failed,Because the  user Aiready exist");
              }
              int result = 0; //受影响的行数默认为0
              try {
                  result = userDao.add(user);
              } catch (Exception e) {
                  System.out.println("添加用户失败,用户已经存在");
                  //其他用户添加失败异常
                  throw new OtherThingsException(e);
              }
              if (result > 0)
                  System.out.println("添加用户成功");
          }
          
          //···省略的其他方法···
          
      }
      
      
      • 老规矩,写完每个Service后,都需要针对具体的对象的行为进行单元测试,UserServiceTest.java代码如下:
      public class UserServiceTest extends BaseTest {
          @Autowired
          private UserServiceImpl userService;    
          //此处直接使用UserService的实现类,主要是方便抛出异常,然后异常出现时候可以针对性的处理
          
          @Test
          public void testAdd() {
              User user = new User();
              try {
                  userService.add(user);
              } catch (UserCanNotBeNullException e) {
                  //用户不能为空异常抛出
                  e.printStackTrace();
              } catch (UserNameCanNotBeNullException e) {
                  //用户名不能为空
                  e.printStackTrace();
              } catch (UserPwdCanNotBeNullException e) {
                  //用户密码不能为空
                  e.printStackTrace();
              } catch (UserAireadyExistException e) {
                  //用户存在抛出
                  e.printStackTrace();
              } catch (OtherThingsException e) {
                  //其他综合异常或是不能处理的异常
                  e.printStackTrace();
              }
          }
          
          //···省略的其他测试代码···
      }
      
      • 同样的,我们的Service的测试代码执行后,我们可以在mysql中看到具体的数据变化,也不再一一贴图了。

因为篇幅和时间原因,我们暂时就不写具体功能的详细实现了,毕竟学习不是一朝一夕,多培养思维才是重要的事情。从这一期开始代码逐渐增多,毕竟学习过程就是这样的递增的,等熟悉以后可能很多地方就更多是培养思维方式,代码就直接贴上(详细的注释不会少)。


这一期总结:

  • 解决项目框架冲突解决,各个框架职能的简单介绍。
  • 简单的原理解释。
  • java web经典mvc、三层架构简单介绍。
  • 部分简单的SQL语句。
  • 针对Dao层和Service层的单元测试。
  • 简单业务实现的流程分析。

下期预告:我们实现详细的功能和Controller(Url请求分发),同时分出API接口为以后打下基础。

项目地址:点击访问github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容