【Spring+SpringMVC+Mybatis】利用SSM整合,完成使用者登入、註冊、修改密碼系統
近年來,由於Struts2+Hibernate3+Spring3,這套SSH框架,Struts2屢次爆出安全漏洞,Hibernate就只會推行它HQL那套而越來越遠離SQL查詢關係資料庫的本質,所以Spring+SpringMVC+Mybatis這套SSM框架悄然興起,現階段在Javaee領域,有種新專案必選SSM的趨勢。本文將利用一個簡單的例子,具體如下圖所示,其實也就是把《【Struts2+Hibernate3+Spring3】利用SSH整合,完成列印使用者表,使用者登入、註冊、修改密碼系統》(點選開啟連結)中的SSH例子再用SSM再做一次,同時檢視儘可能地不雜糅其它技術,以最短的程式碼,給大家展示Spring、SpringMVC、Mybatis三者整合的例子。
一、SSM的下載和配置
在Eclipse新建一個JavaEE的Dynamic Web Project估計已經不用說了,接下來我就不用什麼Maven了,自己配好所有必須的jar包,具體如下。
1、Spring和SpringMVC的下載和配置
其實Spring和SpringMVC所用的jar包都是相同的,畢竟Spring他希望自己一套吃遍Java的所有領域,但Spring做Java和xml互動、近年來SpringMVC做Java和JSP的互動做得最為突出,所以流行起來了。
Spring3.x的使用首先需要commons-logging-1.2.jar這玩意,這個commons-logging-1.2.jar是所有jar的前提,不然,你的java應用只有jar的話,spring根本啟動不了,最直接的表現是配置了spring的javaee應用的tomcat啟動不來。
所以,你要先下載commons-logging-1.2.jar。這玩意直接在Apache Tomcat的官網有,不是很明白為何不直接搞到Tomcat裡面。
下載之後解壓,直接取走裡面的commons-logging-1.2.jar到你的java應用。
commons-logging-1.2-javadoc.jar是個API說明文件,並沒有什麼卵用。
接下來,才是下載Spring3.x。Spring的包全部放到http://repo.spring.io/裡面了,在Spring的官網,http://spring.io你只會看到你並希望Maven下載和一大堆說明文件,頂多是最新版Github託管而已。
進入了spring的資源庫之後,如下圖,找到libs-release-local(這spring都不知道怎麼想的,堂堂的javaee大廠,資源庫裡面的東西竟然不是按a-z排的)->org->springframework->spring->3.2.18 release然後選擇右上角的download,下載Spring3.x的最終穩定版。
下載之後解壓,在libs中,取走所有最終應用,關於API說明*-javadoc.jar、原始碼*-sources.jar完全可以不需要。
2、JDBC和Mybatis的下載
JDBC請選擇合適自己資料庫的版本,本文用Mysql做例子,所以選擇的是Mysql的JDBC。你首先需要兩個jar,一個是連線Mysql必須的jar,這裡以Mysql做例子,Orcale等資料庫則換成相應的jar包即可,可以到Mysql的官網下載:https://dev.mysql.com/downloads/connector/j/,下載之後取走其中的mysql-connector-java-5.1.44-bin.jar到你的工程目錄,一般在工程目錄新建一個lib,放這些包。
然後下載Mybatis,最新的Mybatis是放在Github託管的,網址:https://github.com/mybatis/mybatis-3/releases,同樣取走裡面的核心jar,放到你的工程目錄的WEB-INF\lib下。
3、Mybatis和Spring互動包
最後補上這個jar就OK了。
整合之後WEB-INF\lib資料夾如下所示:
二、目錄結構和所使用的資料庫表
按照上述過程配好在WEB-INF\lib配好jar包之後,先貼上我最終完工的工程目錄結構:
還有我使用的資料庫表,還是這張早已舉個栗子舉爛的Mysql中test資料庫的User使用者表,隨便開個Mysql,建立張user表,資料庫test弄出來的。
三、配置檔案xml的編寫
1、我們先從這個Javaee工程的總配置檔案web.xml看起,所有Javaee工程必有這個檔案。在這個檔案中,主要是宣告使用SpringMVC、Spring還有這個網站主要使用UTF-8編碼,避免亂碼。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 啟用SpringMVC -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 指明Spring配置的初始化檔案 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!-- 字元編碼過濾器 -->
<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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
</web-app>
這裡的web.xml的初始化,不同於之前《【Spring+Mybatis】Spring整合Mybatis》(點選開啟連結)中,指明在 Java工程Spring的核心配置檔案applicationContext.xml所在目錄時,在contextConfigLocation的值只寫一個applicationContext.xml就行,必須寫明/WEB-INF/applicationContext.xml,不完全寫明,Javaee工程找applicationContext.xml會直接去網站根目錄WebContent找,肯定找不到,同時會出現org.springframework.beans.factory.BeanCreationException之類的錯誤
2、接下來先看SpringMVC-servlet.xml,命名只能這樣寫,畢竟在web.xml,指明的servlet-name就是SpringMVC,這個檔案我在《【SpringMVC】Helloworld》(點選開啟連結)已經詳細寫過了,還是那句話,這篇文章主要是介紹SSM整合的,要是每個技術都寫一次,就顯得沒有重點了。這裡除了要求SpringMVC在actios找servlet以外,同時要求Spring掃描Service層,是因為在action用到Service的類中的方法和資料庫打交道,所以必須要求actions層注入Service。同時掃描test.actions和test.services。
<?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:p="http://www.springframework.org/schema/p"
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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="test.actions" />
<context:component-scan base-package="test.services" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
3、然後是Spring的核心配置檔案applicationContext.xml了,這裡和《【Spring+Mybatis】Spring整合Mybatis》(點選開啟連結)同樣,同時整合JDBC和Mybatis,利用Spring配置資料來源,同時指出Mybatis的核心配置檔案是/WEB-INF/configuration.xml。這裡還利用到Spring整合SpringMVC的自動註解功能,可以用一個@將原來的Spring必須要求的private私有變數+getter+setter,精簡到一個註解+private私有變數即可。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd ">
<!-- Spring連線的JDBC資料來源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useOldAliasMetadataBehavior=true" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 指出Mybatis的核心配置檔案,關於資料庫表和Java檔案的對映寫在裡面 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/WEB-INF/configuration.xml"></property>
</bean>
<!-- 指出資料庫介面方法所在的包 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
autowire="byName">
<property name="basePackage" value="test.dao" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- 啟動Spring MVC的註解功能,完成請求和註解POJO的對映 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
</beans>
這裡/WEB-INF/configuration.xml也必須完全寫明,不能只寫configuration.xml,不然就會出現org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.mybatis.spring.mapper.MapperScannerConfigurer#0' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Cannot resolve reference to bean 'sqlSessionFactory' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/configuration.xml]的報錯,無法啟動tomcat,具體如下圖所示:
4、最後就是Mybatis的配置檔案configuration.xml了,由於Spring的存在,讓configuration.xml可以變得非常簡單,不用像《【Mybatis】Helloworld》(點選開啟連結)裡面寫得這麼長,指出資料庫和Java的對映關係Mapper的所在地即可。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 指明在user這個表中所包含常用sql方法,test/mapper/User.xml是一個指明java方法和sql語法聯絡的xml檔案 -->
<mappers>
<mapper resource="test/mapper/User.xml" />
</mappers>
</configuration>
然後順手在test.mapper包下新建一個User.xml。
四、工程核心檔案的編寫
經歷了上面一大堆配置檔案終於弄好整個Spring+SpringMVC+Mybatis的配置了,接下來開始分門別類地分層嚴格遵循MVC的思想編寫整個Javaee工程的核心檔案了。
1、首先完成剛才順手建立的test.mapper.User.xml。該檔案在《【Mybatis】Helloworld》(點選開啟連結)詳細說過了。主要是寫關於該User表的主要操作和test.dao下的Java方法對應關係。這裡分別有按照username查使用者、增加一個使用者、修改使用者名稱對應密碼的三個方法,也剛好展示Mybatis的增刪改查了。
<?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">
<mapper namespace="test.dao.UserDao">
<select id="findUsersByUsername" resultType="test.entity.User">
select * from user
where username=#{username}
</select>
<!--執行增加操作的SQL語句。id和parameterType分別與IUserOperation介面中的addUser方法的名字和引數型別一致。
useGeneratedKeys設定為"true"表明要MyBatis獲取由資料庫自動生成的主鍵; keyProperty="id"指定把獲取到的主鍵值注入到User的id屬性 -->
<insert id="addUser" parameterType="test.entity.User"
useGeneratedKeys="true" keyProperty="id">
insert into
user(username,password) values(#{username},#{password})
</insert>
<update id="modifyPasswordByUsername" parameterType="test.entity.User">
update user set password=#{password} where username=#{username}
</update>
</mapper>
2、然後馬上來完成test.mapper.User.xml對應的test.dao.UserDao.java,具體如下所示,其實也沒什麼好說,就是一大堆方法的羅列,畢竟dao只是一個數據庫介面而已。這裡唯一需要大家注意的是,在SSM整合的過程中,我們需要對Dao層,標上@Repository的註解,讓Spring能識別這是Dao層。
package test.dao;
import org.springframework.stereotype.Repository;
import test.entity.User;
@Repository
public interface UserDao {
public User findUsersByUsername(String username);
public int addUser(User user);
public int modifyPasswordByUsername(User user);
}
同時也順手完成剛才在test.mapper.User.xml提到的增刪改查的使用和返回型別,實體類test.entity.User.java。這樣的資料庫~Java實體,典型的private+getter+setter結構,相信大家早就見慣不怪了。
package test.entity;
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
4、然後是Service層,也就是事務層,test.services.UserServices.java,這裡主要為Action層提供一系列封裝的方法,拿Action提供的資料操作資料庫,並且處理完返回資料給Action來應對jsp和java的互動,這往往是網頁工程的核心。
這裡一樣要嚴格註解一個@Service表示這是個事務層,不然Spring是直接識別不到報錯的。
package test.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import test.dao.UserDao;
import test.entity.User;
@Service
public class UserServices {
@Autowired
private UserDao userDao;//自動注入的存在,無需getter和setter了
/*各個業務*/
//判斷使用者是否存在
public boolean isUserExist(String username) {
if (userDao.findUsersByUsername(username) == null) {
return false;
} else {
return true;
}
}
//根據提供的使用者名稱拿密碼
public String getPasswordByUsername(String username) {
return userDao.findUsersByUsername(username).getPassword();
}
//新增一個使用者
public void addUser(String username, String password) {
User user = new User();
user.setUsername(username);
user.setPassword(password);
userDao.addUser(user);
}
//修改某一使用者的密碼
public void modifyPasswordByUsername(String username, String newpassword) {
User user = userDao.findUsersByUsername(username);
user.setUsername(username);
user.setPassword(newpassword);
userDao.modifyPasswordByUsername(user);
}
}
另外,大家也可以從這個檔案看到Mybatis比Hibernate優秀的原因,Mybatis處理資料庫根本就沒有什麼commit不commit的提交事務才能修改資料庫事情!他就是一個簡單的SQL過程,上面的呼叫的dao方法,你完全可以理解成,這其實就是mapper一條對資料庫操作的sql語句,執行即更改。
5、之後是test.actions.WebAction.java,這裡也就是網頁的Action層了,這個檔案也在《【SpringMVC】Helloworld》(點選開啟連結)中詳細表述過了。
這裡在SSM同樣要明確地加上@Controller註解表示這是個Action層。
這裡也同時展示了SpringMVC中Java是如何拿前臺的資料,和返回資料到前臺的。拿前臺的資料主要是靠@RequestParam("前臺表單的name")+後臺Java的變數名了這個註解,當然還有拿其它資料的方式,不過這個是拿Post方法提交的表單資料最常用了,當然在get提供也可以照樣拿,其餘幾種拿前臺資料的方式比較少用,大家有興趣可以某度一下。@RequestMapping註解指明servlet的url和get/post的使用方式。
而返回資料到前臺,主要壓在model裡面,model可以放任何型別的東西,也就是objects。model可以用jsp3.0簡單的表示式${}列印,要是裡面放的是個list可以配合c標籤來列印。
至於各個方法如何處理使用者登入、註冊、修改密碼的細節,相信大家配合上面的test.services.UserServices.java一下就看得懂了,一點都不難,非常簡單的邏輯判斷。
package test.actions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import test.services.UserServices;
@Controller
public class WebAction {
@Autowired
private UserServices userServices;//自動注入的存在,getter和setter見鬼去吧!
//跳轉到本工程主頁的action
@RequestMapping(value = "/index")
public String index() {
return "index";
}
//關於使用者登入的表單提交
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@RequestParam("username") String username,
@RequestParam("password") String password, ModelMap model) {
if (!userServices.isUserExist(username)) {
model.addAttribute("msg", "使用者名稱不存在!");
} else {
if (password.equals(userServices.getPasswordByUsername(username))) {
model.addAttribute("msg", "登入成功!");
} else {
model.addAttribute("msg", "密碼錯誤!");
}
}
return "index";
}
//關於使用者註冊的表單提交
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(@RequestParam("username") String username,
@RequestParam("password") String password, ModelMap model) {
if (userServices.isUserExist(username)) {
model.addAttribute("msg", "使用者名稱已存在!");
} else {
userServices.addUser(username, password);
model.addAttribute("msg", "註冊成功!");
}
return "index";
}
//關於修改密碼的表單提交
@RequestMapping(value = "/modifyPassword", method = RequestMethod.POST)
public String modifyPassword(@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("newpassword") String newpassword, ModelMap model) {
if (!userServices.isUserExist(username)) {
model.addAttribute("msg", "使用者名稱不存在!");
} else {
if (password.equals(userServices.getPasswordByUsername(username))) {
userServices.modifyPasswordByUsername(username, newpassword);
model.addAttribute("msg", "修改密碼成功!");
} else {
model.addAttribute("msg", "密碼錯誤!");
}
}
return "index";
}
}
6、最後完成view\index.jsp這一頁就大功告成了,views層也就是前端,非常簡單的東西,不多贅述了。本文為了只是用jsp3.0的表示式簡單列印了的string變數${msg},那些什麼列印使用者表就不做。要是model裡面放的是個list,可以參考《【Servlet】利用Servlet3.0標準與JSTL表示式實現檔案上傳系統,支援圖片上傳後顯示》(點選開啟連結)利用jstl表示式的c標籤,<c:foreach>列印了,這裡為了不雜糅jstl的技術,就不展示怎麼列印使用者表了。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>主頁</title>
</head>
<body>
<p style="color:red">${msg}</p><hr>
使用者登入<br>
<form action="login" method="post">
使用者名稱:<input type="text" name="username" /><br>
密碼:<input type="password" name="password" /><br>
<input type="submit" value="提交"><br>
</form><hr>
使用者註冊<br>
<form action="register" method="post">
使用者名稱:<input type="text" name="username" /><br>
密碼:<input type="password" name="password" /><br>
<input type="submit" value="提交"><br>
</form><hr>
修改密碼<br>
<form action="modifyPassword" method="post">
使用者名稱:<input type="text" name="username" /><br>
密碼:<input type="password" name="password" /><br>
新密碼:<input type="password" name="newpassword" /><br>
<input type="submit" value="提交"><br>
</form><hr>
</body>
</html>
最後,本文完成的例子可以在:http://download.csdn.net/download/yongh701/10124309,要是你的csdn下載分不多,或者我一樣很反感csdn的最新的必須要下載分才能下載的下載機制,也可以到https://github.com/yongh701/SSM下載。
大家看到這樣一套下來,Spring+SpringMVC+Mybatis比Struts2+Hibernate3+Spring3更接地氣,沒有什麼s標籤,沒有什麼又要多開一個xml檔案配action,也沒有hibernate那套什麼hql,完完全全就是你最常用的html語言和sql查詢。所以SSM逐漸流行起來了,其實在2014年甚至更早的時候,大家都已經對Struts2、Hibernate3頗有微詞,而隨著Spring的普及,中文資料漸漸增多,它已經不再單純是一個java~xml互動工具。簡單的註解方法,避免以前大量的xml檔案編寫,SpringMVC的高安全性,更加讓SSM成為業內的新寵!