[手把手教程][JavaWeb]SSM框架驗(yàn)證坷牛、修復(fù)和實(shí)例

[手把手教程][JavaWeb]SSM框架驗(yàn)證零如、修復(fù)和實(shí)例

手把手驗(yàn)證上期的SSM項(xiàng)目:優(yōu)雅的SpringMvc+Mybatis整合之路框架。

  • 說實(shí)話硬毕,這一期也應(yīng)該算是上一期的呻引,但是這起需要單獨(dú)拿出來的原因有幾個(gè),最重要的是我個(gè)人討厭長篇大論吐咳。(最簡(jiǎn)單的就是直接丟項(xiàng)目)
  • 但是苞七,直接丟出來,未免太過粗糙挪丢,也不能體驗(yàn)出我們編程的思維養(yǎng)成,故此一步一步的走出來卢厂。
  • 對(duì)于很多哥們催更的事情乾蓬,這個(gè)確實(shí)也不是那么容易出來的,前面的框架搭建是從網(wǎng)上找的資料一步一步的組合的慎恒,但是實(shí)際使用還是有很多問題任内,本篇文章將會(huì)解決這些問題。
  • 同時(shí)融柬,兄弟們稍微耐心點(diǎn)死嗦,我這邊也是一點(diǎn)點(diǎn)實(shí)現(xiàn),還請(qǐng)客官們放下手中的西瓜刀粒氧。
  • 再次安利一波,博客地址:acheng1314.cn

工具

  • IDE為idea15
  • JDK環(huán)境為1.8
  • maven版本為maven3
  • Mysql版本為5.5.27
  • Tomcat版本為7.0.52

本期目標(biāo)

  • 項(xiàng)目框架介紹和沖突解決越除。
  • 實(shí)例Service和Dao。項(xiàng)目框架測(cè)試外盯。
  • 登錄摘盆、注冊(cè)業(yè)務(wù)的分析、創(chuàng)建和演示饱苟。

沖突解決

為什么我把沖突解決放在第一位孩擂?

因?yàn)樵跊_突解決后,我們可以進(jìn)入測(cè)試階段箱熬,同時(shí)在解決沖突的時(shí)候类垦,我們會(huì)一點(diǎn)點(diǎn)的體會(huì)到SSM項(xiàng)目框架中各個(gè)框架之間是怎么協(xié)同工作的狈邑,也就可以完成項(xiàng)目介紹。

重要的是蚤认,在實(shí)際生活中米苹,我們?nèi)ス旧习啵话阋彩窍冉鉀Q項(xiàng)目框架沖突問題烙懦。

  • 打開項(xiàng)目后驱入,隨意選擇一個(gè)Spring的配置文件,會(huì)彈出如下界面:

    ssm框架檢測(cè)第一步
    ssm框架檢測(cè)第一步

    我們點(diǎn)擊圖中右上角圈出來部分氯析,會(huì)彈出如下界面:

    ssm框架檢測(cè)第二步
    ssm框架檢測(cè)第二步

    這里我們什么都不需要做亏较,直接點(diǎn)擊OK

    上面兩步是為了告訴Idea我們的Spring配置文件在哪掩缓。類似單一Spring配置文件的ApplicationContext.xml一樣雪情,我們只是將Spring根據(jù)模塊分發(fā)而已。

  • 在Tomcat中運(yùn)行本項(xiàng)目你辣,運(yùn)行結(jié)果應(yīng)該是在瀏覽器中顯示Hello World界面巡通。

    • 配置Tomcat

    • 配置項(xiàng)目的Tomcat啟動(dòng)設(shè)置。

    • 參考連接:點(diǎn)擊進(jìn)入

    • 在web瀏覽器中輸入:localhost:8080/druid 舍哄,查看druid是否配置成功宴凉。

      ssm框架檢測(cè)第三步
      ssm框架檢測(cè)第三步

      如上面的圖中,我們可以看到我們的druid并沒有把JDBC驅(qū)動(dòng)列出來表悬。這說明我們的項(xiàng)目的JDBC驅(qū)動(dòng)要么沒有設(shè)置弥锄,要么是數(shù)據(jù)庫驅(qū)動(dòng)的配置文件沒做好。

    • 隨意輸入一個(gè)localhost:8080/下的地址蟆沫,至此我們要展示錯(cuò)誤404頁面籽暇。并且把Tomcat不友好的404頁面替換。

      • 替換思路:錯(cuò)誤404這種常出現(xiàn)的頁面饭庞,我們可以設(shè)置為靜態(tài)資源戒悠,以加快網(wǎng)頁訪問。

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

        <servlet-mapping>
            <servlet-name>mvc-dispatcher</servlet-name>
            <!-- 默認(rèn)匹配所有的請(qǐng)求 -->
            <!-- 我們默認(rèn)配置這個(gè)是為了讓我們的Spring框架接管Servelt绸狐,實(shí)現(xiàn)Spring控制所有站點(diǎn)請(qǐng)求 -->
            <url-pattern>/</url-pattern>
            <!--<url-pattern>/css/*</url-pattern>-->
            <!--<url-pattern>/images/*</url-pattern>-->
            <!--<url-pattern>/fonts/*</url-pattern>-->
        </servlet-mapping>
        

        配置了web.xml后,我們重啟重啟應(yīng)用累盗,輸入一個(gè)錯(cuò)誤的地址(跳轉(zhuǎn)到404頁面)六孵,會(huì)發(fā)現(xiàn)提示錯(cuò)誤信息,主要報(bào)錯(cuò)如下

         Exception encountered during context initialization - cancelling refresh attempt: 
            org.springframework.beans.factory.BeanCreationException: 
                Error creating bean with name 'dataSource' defined in file [項(xiàng)目所在的物理地址\WEB-INF\classes\spring\spring-dao.xml]: 
                    Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/slf4j/Logger
            
            //上面這個(gè)錯(cuò)誤主要是提示我們:NoClassDefFoundError: org/slf4j/這個(gè)類找不到幅骄。
        
        解決辦法:偷懶的把log4j2從maven配置文件中刪除了劫窒,開啟了logback,在maven的pom.xml中:
            
            <!-- 1.日志 -->
            <!--<!– 實(shí)現(xiàn)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主巍,等項(xiàng)目部署完成后冠息,我們?cè)俅未蜷_,再次輸入錯(cuò)誤地址孕索,我們發(fā)現(xiàn)還是在報(bào)錯(cuò)逛艰,信息如下:

        Exception encountered during context initialization - cancelling refresh attempt: 
            org.springframework.beans.factory.BeanCreationException: 
                Error creating bean with name 'sqlSessionFactory' defined in file [項(xiàng)目物理地址\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
                            
            根據(jù)上面的提示信息,我們可以看到提示的是mapper下面沒有文件搞旭,那么我們就給他制定一個(gè)空的配置文件(BaseDao.xml)散怖,內(nèi)容如下:
            
                <?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>
        

        同樣的肄渗,我們?cè)俅沃貑⒎?wù)器镇眷,并且輸入錯(cuò)誤的地址,現(xiàn)在能正常顯示錯(cuò)誤404的頁面了翎嫡,但是頁面太過Low了欠动,我們得重寫一下web.xml的配置。404頁面如下所示:

        ssm框架檢測(cè)404模版頁面
        ssm框架檢測(cè)404模版頁面

        解決思路:錯(cuò)誤404的頁面是常用頁面之一惑申,所以我們?cè)陧?xiàng)目的資源目錄(webapp)下創(chuàng)建一個(gè)static目錄具伍,專門用來存放靜態(tài)資源,如js圈驼、css人芽、錯(cuò)誤提示頁面、登錄绩脆、注冊(cè)頁面等等萤厅。

        通過網(wǎng)上查閱資料,我們看到大部分人都是把404頁面提示信息提交給Servelt自己管理衙伶,我們也依樣畫瓢,在web.xml中配置害碾,如下:
        <error-page>
            <error-code>404</error-code>
            <Location>/static/view/404.html</Location>
        </error-page>
        

        同時(shí)矢劲,我們需要給Spring寫一個(gè)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注解模式 -->
            <!-- 簡(jiǎn)化配置:
                (1)自動(dòng)注冊(cè)DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter
                (2)提供一些列:數(shù)據(jù)綁定芬沉,數(shù)字和日期的format @NumberFormat, @DateTimeFormat, xml,json默認(rèn)讀寫支持
            -->
            <mvc:annotation-driven/>
            <!-- 2.靜態(tài)資源默認(rèn)servlet配置
                (1)加入對(duì)靜態(tài)資源的處理: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相關(guān)的bean配置 -->
            <context:component-scan base-package="cn.acheng1314.mvc">
                <!-- 制定掃包規(guī)則 ,只掃描使用@Controller注解的JAVA類 -->
                <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            </context:component-scan>
        
        </beans>
        

        以上文件配置好后,我們重啟服務(wù)器阁猜,并輸入錯(cuò)誤地址丸逸,現(xiàn)在我們插入的404頁面正常顯示了。

        通過上面的資料剃袍,我們可以大膽整理下web請(qǐng)求的思路:

        用戶發(fā)起請(qǐng)求→DNS解析發(fā)現(xiàn)服務(wù)器→建立鏈接發(fā)送請(qǐng)求→WEB服務(wù)器分發(fā)給應(yīng)用服務(wù)器→MVC層框架處理請(qǐng)求過程→返回?cái)?shù)據(jù)給用戶

        而上面的SpringMvc作為框架層黄刚,我們也可以通過網(wǎng)上資料和我們目前的配置做出一些構(gòu)想:

        Tomact分發(fā)請(qǐng)求→Servelt收到請(qǐng)求→Spring接管Servelt→DispatcherServlet處理請(qǐng)求分發(fā)→根據(jù)Spring配置找到對(duì)應(yīng)的控制器(Controller)處理業(yè)務(wù)→返回對(duì)應(yīng)數(shù)據(jù)。

        而下面有一張更加突出的圖片說明了這一切:

        SpringMVC詳細(xì)運(yùn)行流程圖

        總結(jié):目前項(xiàng)目中的靜態(tài)資源我們已經(jīng)處理完畢民效,加入了一部分Web的靜態(tài)資源憔维,增加了Spring的web處理配置涛救,修改了web.xml,log4j2替換為LogBack,Junit版本提升為4.12业扒,加入了一個(gè)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>
              <!-- 默認(rèn)匹配所有的請(qǐng)求 -->
              <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強(qiáng)制程储,促使 -->
              <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方式監(jiān)控配置-->
          <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框架實(shí)例--倉庫管理系統(tǒng)--登錄注冊(cè)的功能分析

分析:

  • 登錄和注冊(cè),都是用戶的行為章鲤,也是我們開發(fā)中常說的某個(gè)行為對(duì)應(yīng)的業(yè)務(wù)摊灭。
  • 注冊(cè)用戶,意味著添加用戶咏窿,添加了用戶后斟或,我們才有登錄功能的繼續(xù)執(zhí)行的可能。
  • 用戶登錄集嵌,也是用戶信息的查找和比對(duì)過程萝挤。一般來說用戶先把信息提交給程序,然后程序按照流程執(zhí)行后提交數(shù)據(jù)給服務(wù)器這個(gè)流程中程序可能會(huì)產(chǎn)生一些業(yè)務(wù)邏輯的判斷)根欧,服務(wù)器收到數(shù)據(jù)并進(jìn)行數(shù)據(jù)對(duì)比怜珍,當(dāng)用戶信息存在且?guī)ぬ?hào)和密碼匹配才能登錄成功,否則前面的任意條件不滿足即為登錄失敗凤粗。
  • 我們可以依靠單一的用戶表來實(shí)現(xiàn)用戶的登錄數(shù)據(jù)獲取注冊(cè)信息的添加酥泛。

功能大概分析完畢后,我們就可以考慮下如何實(shí)現(xiàn)這些功能嫌拣。大概圖示如下:

ssm框架經(jīng)典三層分析
ssm框架經(jīng)典三層分析
  • 首先用戶信息需要存儲(chǔ)柔袁,我們需要數(shù)據(jù)庫的支撐。
  • 有了數(shù)據(jù)庫的支援后异逐,我們需要先測(cè)試用戶信息的添加和查找捶索。就是我們常說的Dao層。
  • 當(dāng)我們的Dao層拿到想要的數(shù)據(jù)灰瞻,我們需要Service層將Dao層的操作作為服務(wù)提供給控制器腥例,再由控制器提供給前臺(tái)頁面。
  • 同樣的用戶需要獲取某個(gè)數(shù)據(jù)酝润,先是瀏覽器獲取到用戶請(qǐng)求→web層→Service層→Dao層燎竖,再接著重復(fù)上面的操作。

上面一張圖用模型已經(jīng)很好的說明了java web后端各層的關(guān)系要销,下面一張圖是經(jīng)典三層對(duì)照MVC的描述构回。

ssm框架經(jīng)典三層分析對(duì)照Mvc
ssm框架經(jīng)典三層分析對(duì)照Mvc

上面的圖引用自互聯(lián)網(wǎng)資料,下面的黑色字是我添加上去的。

  • 上面圖中捐凭,我們可以看到一部分MVC設(shè)計(jì)和圖中標(biāo)記的類似拨扶,但是這只是一種MVC模式的栗子。

  • 關(guān)于更加詳細(xì)的MVC茁肠,我們可以百度百科查看患民。


上面提到的東西,我們適可而止就行了垦梆,很多東西現(xiàn)在還不是深究的時(shí)候匹颤,我們要先懂一個(gè)事物的外在表現(xiàn),才有進(jìn)一步的探索托猩,所以我們需要等緣分的到來印蓖。

SSM框架實(shí)例--倉庫管理系統(tǒng)--注冊(cè)、登錄的功能模擬實(shí)現(xiàn)

按照前面我們的分析來講京腥,我們需要先考慮Dao層的實(shí)現(xiàn)赦肃,畢竟有了Dao層對(duì)數(shù)據(jù)的封裝,才可以有后面的操作公浪,所以后面我的栗子中他宛,一切都是按照Dao→Service→Controller→View這樣的一個(gè)步驟來實(shí)現(xiàn)。

  • 用戶注冊(cè)功能的Dao層實(shí)現(xiàn)欠气。
    • 數(shù)據(jù)庫基本操作為:增刪改查厅各。

    • 我們根據(jù)數(shù)據(jù)庫常規(guī)操作的類型,分別對(duì)其進(jìn)行抽象预柒,所以產(chǎn)生了Dao.java這個(gè)接口對(duì)象的基本模型队塘。代碼如下:

      /**
       * 通過接口編程
       * @param <T> 泛型用于解耦,同時(shí)避免寫重復(fù)代碼
       */
      public interface Dao<T> {
          /**
           * 添加某個(gè)對(duì)象
           * @param t 待添加的對(duì)象
           * @return  返回受影響的行數(shù)
           */
          int add(T t);
      
          /**
           * 刪除某個(gè)對(duì)象宜鸯,在企業(yè)開發(fā)中憔古,我們一般不做物理刪除,只是添加某個(gè)字段對(duì)其數(shù)據(jù)進(jìn)行可用控制
           * @param t 待刪除對(duì)象
           * @return 返回受影響的條數(shù)
           */
          int  del(T t);
      
          /**
           * 更新某個(gè)對(duì)象
           * @param t 待更新對(duì)象
           * @return 返回受影響的條數(shù)
           */
          int update(T t);
      
          /**
           * 通過ID查找一個(gè)對(duì)象
           * @param Id    待查詢的對(duì)象的ID
           * @return  返回該ID對(duì)應(yīng)的對(duì)象
           */
          T findOneById(Serializable Id);
      
          /**
           * 查找對(duì)象集合
           * @return  返回對(duì)象集合
           */
          List<T> findAll();
      }
      
    • 實(shí)現(xiàn)用戶的Dao層:

      • 我們要針對(duì)用戶寫用戶的Dao層淋袖,我們需要有一個(gè)用戶對(duì)象的封裝鸿市,直接在domain包下面創(chuàng)建User.java,代碼如下:
      /***
      創(chuàng)建數(shù)據(jù)庫用戶表:
       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 '職務(wù)',
       `cell_number` varchar(15) COMMENT '手機(jī)號(hào)',
       `photo_url` varchar(75) COMMENT '頭像地址',
       `used` boolean NOT NULL COMMENT '賬號(hào)是否可用',
       PRIMARY KEY (`login_id`)
       ) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='用戶表';
      
       插入默認(rèn)數(shù)據(jù):
       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;    //職務(wù)
          private int age;    //年齡
          private String cellNumber;  //手機(jī)號(hào)
          private String photoUrl;    //頭像地址
          private boolean used = true;   //是否可用,默認(rèn)值是true
          
          ···省略get适贸、set和toString
      }    
      
      //推薦大家把每個(gè)bean對(duì)應(yīng)的數(shù)據(jù)庫操作備注到上面灸芳。
      //打開Navicat For Mysql涝桅,鏈接上數(shù)據(jù)庫拜姿,創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)庫,并運(yùn)行上面的sql產(chǎn)生數(shù)據(jù)庫表和初始記錄冯遂。
      
      • 當(dāng)我們數(shù)據(jù)庫創(chuàng)建完畢后蕊肥,我們需要寫一個(gè)接口對(duì)user表進(jìn)行操作封裝。我們?cè)赿ao包下面創(chuàng)建UserDao接口,代碼如下:
      /**
       * 在傳統(tǒng)的jdbc操作中壁却,我們需要手動(dòng)管理數(shù)據(jù)庫連接的開關(guān)批狱,數(shù)據(jù)庫資源訪問的開關(guān)等等
       * <br/>但是,我們這里采用了Mybatis和Druid這兩個(gè)框架,那么我們可以完全不必理會(huì)數(shù)據(jù)庫連接等等的控制展东,
       * <br/>我們只需要更加專注于業(yè)務(wù)實(shí)現(xiàn)的開發(fā)赔硫。
       */
      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的封裝后,傳統(tǒng)的操作這一步需要自己手動(dòng)實(shí)現(xiàn)UserDao的Impl盐肃,并實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的操作等等爪膊。而我們使用Mybatis后,UserDao的Impl在Mybatis的mapper文件夾中指定為xml砸王,我們的Dao文件除了數(shù)據(jù)庫操作的語句其他的都無需關(guān)注,那么剩下的數(shù)據(jù)庫操作什么的我們都無需關(guān)心推盛,畢竟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已經(jīng)完成谦铃,這就意味著我們的UserDao基本完成耘成,那么我們應(yīng)該來一次單元測(cè)試來看看效果如何。UserDaoTest.java如下:
      @RunWith(SpringJUnit4ClassRunner.class) //spring的單元測(cè)試
      @ContextConfiguration({"classpath:spring/spring-*.xml"})    //上下文配置
      public class UserDaoTest {
      
          @Autowired
          private UserDao userDao;    //初始化Dao層驹闰,面向接口編程
          
          /**
          * 添加用戶的單元測(cè)試瘪菌,添加成功與否會(huì)有對(duì)應(yīng)的提示。
          * 當(dāng)然按照我這個(gè)配置一般會(huì)正確疮方,如果說出錯(cuò)就需要你一步一步的看錯(cuò)誤的提示代碼了控嗜。
          * 添加同樣的LoginId的用戶會(huì)添加失敗,因?yàn)樵谏厦姘袻oginId作為了數(shù)據(jù)庫表的主鍵骡显。
          */
          @Test
          public void testAdd() {
              User user = new User();
              user.setLoginId("pc147852369");
              user.setName("雨下一整夜");
              user.setPwd("123456");
              user.setSex("未知");
              int result = 0; //受影響的行數(shù)默認(rèn)為0
              try {
                  result = userDao.add(user);
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("添加用戶失敗");
              }
              if (result>0)
                  System.out.println("添加用戶成功");
          }
          
          /**
          * 查找用戶測(cè)試疆栏,成功與否會(huì)有l(wèi)og輸出
          */
          @Test
          public void testFindOneId() throws Exception {
              User user = new User();
              user.setLoginId("pc147852369");
              User result = null; //受影響的行數(shù)默認(rèn)為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; //受影響的行數(shù)默認(rèn)為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; //受影響的行數(shù)默認(rèn)為0
              try {
                  result = userDao.update(user);
              } catch (Exception e) {
                  e.printStackTrace();
                  System.out.println("更新用戶信息用戶失敗");
              }
              if (result>0)
                  System.out.println("更新用戶信息用戶成功");
      
          }
      }
      

      數(shù)據(jù)的操作結(jié)果我們都可以在mysql中查看,這里就不一一截圖了惫谤。當(dāng)然我們也可看到每次單元測(cè)試都需要在類上面注解spring單元測(cè)試和spring的上下文壁顶,按照我們編程的原則,一次編碼處處運(yùn)行溜歪,我們可以把這些注解放到BaseTest.java中若专,后面所有的單元測(cè)試都繼承BaseTest.java即可避免大量重復(fù)編碼

    • UserService實(shí)現(xiàn)(注意編程思維的養(yǎng)成)

      • 根據(jù)我們面向接口編程的思維來講蝴猪,我們?cè)赟ervice中核心是實(shí)現(xiàn)Dao層调衰,并調(diào)用Dao層。
      • 剛才我們單元測(cè)試自阱,我們的UserDao層通過測(cè)試了嚎莉,我們現(xiàn)在中心就應(yīng)該放在業(yè)務(wù)邏輯的實(shí)現(xiàn),而不是繼續(xù)糾纏Dao層沛豌,畢竟數(shù)據(jù)持久化已經(jīng)實(shí)現(xiàn)了趋箩。
      • 從服務(wù)端程序的角度看來,用戶的主要業(yè)務(wù)有注冊(cè)、登錄叫确、注銷登錄跳芳、注銷帳號(hào)等等,這里我們先拿注冊(cè)來說事竹勉。

      • 用戶注冊(cè)流程分析(用戶角度):
        • 填寫帳號(hào)相關(guān)信息
        • 提交注冊(cè)信息
        • 服務(wù)器返回是否注冊(cè)成功
      • 用戶注冊(cè)流程分析(服務(wù)器角度):
        • 收到用戶注冊(cè)請(qǐng)求
        • 解包數(shù)據(jù)→封裝到UserBean
          • 解包數(shù)據(jù)失敗(請(qǐng)求信息異常)飞盆,返回錯(cuò)誤提示信息
        • 針對(duì)具體的用戶信息檢查是否符合標(biāo)準(zhǔn)
          • 不符合檢查標(biāo)準(zhǔn),返回對(duì)應(yīng)的錯(cuò)誤提示
        • 通過檢查次乓,調(diào)用Dao檢查是否存在同樣的用戶
          • 數(shù)據(jù)庫已經(jīng)存在相同的用戶信息桨啃,不能重復(fù)添加,返回錯(cuò)誤提示信息
        • 不存在同樣的用戶檬输,添加新用戶照瘾,并返回成功的提示信息

      流程圖反映如下:

      ssm框架用戶行為解析流程圖
      ssm框架用戶行為解析流程圖
      • 代碼實(shí)現(xiàn)用戶注冊(cè)的Service:
      //創(chuàng)建一個(gè)BaseService接口,用泛型解耦
      public interface UserService extends BaseService<User> {
          //添加用戶的實(shí)例
          void add(User user) throws Exception;
      }
      
      ------------------------------分割線----------------------------------
      
      //創(chuàng)建一個(gè)UserService繼承BaseService丧慈,并指定具體的實(shí)體類型
      //為什么要再寫一個(gè)UserService接口析命?不同對(duì)象的業(yè)務(wù)體系不同,BaseService并不能完全替代不同對(duì)象的具體行為表現(xiàn)
      public interface UserService extends BaseService<User> {
      
          void add(User user) throws Exception;
      }
      
      ------------------------------分割線----------------------------------
      
      //創(chuàng)建UserServiceImpl實(shí)現(xiàn)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");
              }
              //由于我這個(gè)是倉庫管理系統(tǒng)完域,根據(jù)業(yè)務(wù)需求來說软吐,我們的用戶基本信息都是不能為空的
              //基本信息包括:姓名、年齡吟税、用戶名凹耙、密碼、性別肠仪、手機(jī)號(hào)肖抱,年齡大于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");
              }
              //已經(jīng)存在相同用戶
              if (null != userDao.findOneById(user.getLoginId())) {
                  //存在相同的用戶異常
                  throw new UserAireadyExistException("Register User Failed,Because the  user Aiready exist");
              }
              int result = 0; //受影響的行數(shù)默認(rèn)為0
              try {
                  result = userDao.add(user);
              } catch (Exception e) {
                  System.out.println("添加用戶失敗,用戶已經(jīng)存在");
                  //其他用戶添加失敗異常
                  throw new OtherThingsException(e);
              }
              if (result > 0)
                  System.out.println("添加用戶成功");
          }
          
          //···省略的其他方法···
          
      }
      
      
      • 老規(guī)矩异旧,寫完每個(gè)Service后意述,都需要針對(duì)具體的對(duì)象的行為進(jìn)行單元測(cè)試,UserServiceTest.java代碼如下:
      public class UserServiceTest extends BaseTest {
          @Autowired
          private UserServiceImpl userService;    
          //此處直接使用UserService的實(shí)現(xiàn)類吮蛹,主要是方便拋出異常荤崇,然后異常出現(xiàn)時(shí)候可以針對(duì)性的處理
          
          @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();
              }
          }
          
          //···省略的其他測(cè)試代碼···
      }
      
      • 同樣的潮针,我們的Service的測(cè)試代碼執(zhí)行后术荤,我們可以在mysql中看到具體的數(shù)據(jù)變化,也不再一一貼圖了然低。

因?yàn)槠蜁r(shí)間原因喜每,我們暫時(shí)就不寫具體功能的詳細(xì)實(shí)現(xiàn)了,畢竟學(xué)習(xí)不是一朝一夕雳攘,多培養(yǎng)思維才是重要的事情带兜。從這一期開始代碼逐漸增多,畢竟學(xué)習(xí)過程就是這樣的遞增的吨灭,等熟悉以后可能很多地方就更多是培養(yǎng)思維方式刚照,代碼就直接貼上(詳細(xì)的注釋不會(huì)少)。


這一期總結(jié):

  • 解決項(xiàng)目框架沖突解決喧兄,各個(gè)框架職能的簡(jiǎn)單介紹无畔。
  • 簡(jiǎn)單的原理解釋。
  • java web經(jīng)典mvc吠冤、三層架構(gòu)簡(jiǎn)單介紹浑彰。
  • 部分簡(jiǎn)單的SQL語句。
  • 針對(duì)Dao層和Service層的單元測(cè)試拯辙。
  • 簡(jiǎn)單業(yè)務(wù)實(shí)現(xiàn)的流程分析郭变。

下期預(yù)告:我們實(shí)現(xiàn)詳細(xì)的功能和Controller(Url請(qǐng)求分發(fā)),同時(shí)分出API接口為以后打下基礎(chǔ)涯保。

項(xiàng)目地址:點(diǎn)擊訪問github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诉濒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夕春,更是在濱河造成了極大的恐慌未荒,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件及志,死亡現(xiàn)場(chǎng)離奇詭異片排,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)速侈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門划纽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锌畸,你說我怎么就攤上這事勇劣。” “怎么了潭枣?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵比默,是天一觀的道長。 經(jīng)常有香客問我盆犁,道長命咐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任谐岁,我火速辦了婚禮醋奠,結(jié)果婚禮上榛臼,老公的妹妹穿的比我還像新娘。我一直安慰自己窜司,他們只是感情好沛善,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著塞祈,像睡著了一般金刁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上议薪,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天尤蛮,我揣著相機(jī)與錄音,去河邊找鬼斯议。 笑死产捞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哼御。 我是一名探鬼主播轧葛,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼艇搀!你這毒婦竟也來了尿扯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤焰雕,失蹤者是張志新(化名)和其女友劉穎衷笋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矩屁,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辟宗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吝秕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泊脐。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖烁峭,靈堂內(nèi)的尸體忽然破棺而出容客,到底是詐尸還是另有隱情,我是刑警寧澤约郁,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布缩挑,位于F島的核電站,受9級(jí)特大地震影響鬓梅,放射性物質(zhì)發(fā)生泄漏供置。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一绽快、第九天 我趴在偏房一處隱蔽的房頂上張望芥丧。 院中可真熱鬧紧阔,春花似錦、人聲如沸续担。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赤拒。三九已至,卻和暖如春诱鞠,著一層夾襖步出監(jiān)牢的瞬間挎挖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工航夺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蕉朵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓阳掐,卻偏偏與公主長得像始衅,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缭保,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容