[手把手教程][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è)第一步我們點(diǎn)擊圖中右上角圈出來部分氯析,會(huì)彈出如下界面:
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è)第三步如上面的圖中,我們可以看到我們的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模版頁面解決思路:錯(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)典三層分析](http://acheng1314.cn/wp-content/uploads/2016/09/ssm%E6%A1%86%E6%9E%B6%E7%BB%8F%E5%85%B8%E4%B8%89%E5%B1%82%E5%88%86%E6%9E%90.png)
- 首先用戶信息需要存儲(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](http://acheng1314.cn/wp-content/uploads/2016/09/ssm%E6%A1%86%E6%9E%B6%E7%BB%8F%E5%85%B8%E4%B8%89%E5%B1%82%E5%88%86%E6%9E%90%E5%AF%B9%E7%85%A7Mvc.png)
上面的圖引用自互聯(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框架用戶行為解析流程圖- 代碼實(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