本項目是作者學習早期的一個項目了,是基於MVC架構(單工程)的一個Spring、SpringMvc、Mybatis的一個框架整合項目
因為之前沒有寫博客的習慣,所以就沒有記錄,現在只是把以前的項目記錄一下,也歡迎大家交流討論!
項目源碼地址 http://git.oschina.net/Lamb7/ssmdemo
建議大家直接去 碼雲 上下載或者clone 源碼,比較直觀
先看一下項目結構
其中下面的src中問webapp
先評價一下這個結構,首先,關於java類的結構,mvc架構基本的骨架是這樣的,(我這里沒寫公司包名,本來包名應該是com.xxxx.xxx.controller等)
但是,現在流行動靜態資源分離,為的是降低web應用的壓力,和大小,而且h5的渲染速度,比jsp快多了。所以本例中的靜態文件資源只是為了方便而已才這么放的。但是想java類,以及配置文件的位置,放的還是比較正確的。接下來開始構建工程
1.使用maven構建項目,引入相關jar(可能有一些jar是多余的,來不及整理)

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 3 4 <!-- 當前pom的版本 --> 5 <modelVersion>4.0.0</modelVersion> 6 7 <!-- 主項目的標識 --> 8 <groupId>ssm_Login</groupId> 9 <artifactId>LoginDemo4</artifactId> 10 <packaging>war</packaging> 11 <version>0.0.1-SNAPSHOT</version> 12 13 <dependencies> 14 <!-- Spring 、SpringMVC 的 相關 jar --> 15 <dependency> 16 <groupId>org.springframework</groupId> 17 <artifactId>spring-core</artifactId> 18 <version>4.3.2.RELEASE</version> 19 </dependency> 20 <dependency> 21 <groupId>org.springframework</groupId> 22 <artifactId>spring-webmvc</artifactId> 23 <version>4.3.2.RELEASE</version> 24 </dependency> 25 <dependency> 26 <groupId>org.springframework</groupId> 27 <artifactId>spring-context</artifactId> 28 <version>4.3.2.RELEASE</version> 29 </dependency> 30 <dependency> 31 <groupId>org.springframework</groupId> 32 <artifactId>spring-tx</artifactId> 33 <version>4.3.2.RELEASE</version> 34 </dependency> 35 <dependency> 36 <groupId>org.springframework</groupId> 37 <artifactId>spring-jdbc</artifactId> 38 <version>4.3.2.RELEASE</version> 39 </dependency> 40 <dependency> 41 <groupId>org.springframework</groupId> 42 <artifactId>spring-beans</artifactId> 43 <version>4.3.2.RELEASE</version> 44 </dependency> 45 <dependency> 46 <groupId>org.springframework</groupId> 47 <artifactId>spring-aop</artifactId> 48 <version>4.3.2.RELEASE</version> 49 </dependency> 50 <dependency> 51 <groupId>org.springframework</groupId> 52 <artifactId>spring-expression</artifactId> 53 <version>4.3.2.RELEASE</version> 54 </dependency> 55 <dependency> 56 <groupId>org.springframework</groupId> 57 <artifactId>spring-test</artifactId> 58 <version>4.3.2.RELEASE</version> 59 </dependency> 60 <dependency> 61 <groupId>org.springframework</groupId> 62 <artifactId>spring-context-support</artifactId> 63 <version>4.3.2.RELEASE</version> 64 </dependency> 65 66 <!-- Servlet 的 jar --> 67 <dependency> 68 <groupId>javax.servlet</groupId> 69 <artifactId>javax.servlet-api</artifactId> 70 <version>3.1.0</version> 71 </dependency> 72 73 <!-- Mybatis 的 jar --> 74 <dependency> 75 <groupId>org.mybatis</groupId> 76 <artifactId>mybatis</artifactId> 77 <version>3.2.8</version> 78 </dependency> 79 80 <!-- Mybatis 和 Spring 整合的 jar --> 81 <dependency> 82 <groupId>org.mybatis</groupId> 83 <artifactId>mybatis-spring</artifactId> 84 <version>1.3.0</version> 85 </dependency> 86 87 88 <!-- Mysql 的 驅動 jar --> 89 <dependency> 90 <groupId>mysql</groupId> 91 <artifactId>mysql-connector-java</artifactId> 92 <version>5.1.30</version> 93 </dependency> 94 95 <!-- alibaba 的數據源 的 jar --> 96 <dependency> 97 <groupId>com.alibaba</groupId> 98 <artifactId>druid</artifactId> 99 <version>1.0.15</version> 100 </dependency> 101 102 <!-- 其它相關的jar --> 103 <dependency> 104 <groupId>aopalliance</groupId> 105 <artifactId>aopalliance</artifactId> 106 <version>1.0</version> 107 </dependency> 108 109 <dependency> 110 <groupId>org.aspectj</groupId> 111 <artifactId>aspectjweaver</artifactId> 112 <version>1.8.6</version> 113 </dependency> 114 115 <!-- log4j 的 jar 包 --> 116 <dependency> 117 <groupId>log4j</groupId> 118 <artifactId>log4j</artifactId> 119 <version>1.2.17</version> 120 </dependency> 121 122 <!-- fastjson的 jar --> 123 <dependency> 124 <groupId>com.alibaba</groupId> 125 <artifactId>fastjson</artifactId> 126 <version>1.2.24</version> 127 </dependency> 128 129 130 131 <!-- 測試相關的 jar --> 132 <dependency> 133 <groupId>junit</groupId> 134 <artifactId>junit</artifactId> 135 <version>4.10</version> 136 <scope>test</scope> 137 </dependency> 138 139 <!-- 使用 responsebody 要使用的jar 包 ,或者直接引入 fastJson--> 140 <dependency> 141 <groupId>com.fasterxml.jackson.core</groupId> 142 <artifactId>jackson-databind</artifactId> 143 <version>2.8.1</version> 144 </dependency> 145 146 </dependencies> 147 148 <build> 149 <finalName>LoginDemo4</finalName> 150 <!-- 為了在 maven update 的時候不讓 jdk 變成1.5 --> 151 <plugins> 152 <plugin> 153 <groupId>org.apache.maven.plugins</groupId> 154 <artifactId>maven-compiler-plugin</artifactId> 155 <version>2.1</version> 156 <configuration> 157 <source>1.7</source> 158 <target>1.7</target> 159 </configuration> 160 </plugin> 161 </plugins> 162 </build> 163 </project>
2.建庫建表

1 -- ---------------------------- 2 -- Table structure for user 3 -- ---------------------------- 4 DROP TABLE IF EXISTS `user`; 5 CREATE TABLE `user` ( 6 `username` varchar(11) NOT NULL, 7 `password` varchar(20) NOT NULL, 8 `id` int(10) NOT NULL AUTO_INCREMENT, 9 `asset` float(10,2) DEFAULT '0.00', 10 `status` smallint(1) DEFAULT '1', 11 `createtime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 12 `updatetime` timestamp NULL DEFAULT NULL, 13 PRIMARY KEY (`id`) 14 ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; 15 16 -- ---------------------------- 17 -- Records of user 18 -- ---------------------------- 19 INSERT INTO `user` VALUES ('15988888888', '55555', '1', '238.00', '1', '2016-09-10 10:39:33', '2016-09-26 11:42:10'); 20 INSERT INTO `user` VALUES ('15977777777', '12', '2', '971.00', '1', '2016-09-10 11:43:19', '2016-09-10 11:43:19');
3.創建實體類 User.java(開始編寫model層)

1 package model; 2 3 import java.util.Date; 4 import java.util.List; 5 6 public class User { 7 8 private Integer id; 9 10 private String username; 11 12 private String password; 13 14 private Float asset; 15 16 private Short status; 17 18 private Date createtime; 19 20 private Date updatetime; 21 22 public Integer getId() { 23 return id; 24 } 25 26 public void setId(Integer id) { 27 this.id = id; 28 } 29 30 public String getUsername() { 31 return username; 32 } 33 34 public void setUsername(String username) { 35 this.username = username == null ? null : username.trim(); 36 } 37 38 public String getPassword() { 39 return password; 40 } 41 42 public void setPassword(String password) { 43 this.password = password == null ? null : password.trim(); 44 } 45 46 public Float getAsset() { 47 return asset; 48 } 49 50 public void setAsset(Float asset) { 51 this.asset = asset; 52 } 53 54 public Short getStatus() { 55 return status; 56 } 57 58 public void setStatus(Short status) { 59 this.status = status; 60 } 61 62 public Date getCreatetime() { 63 return createtime; 64 } 65 66 public void setCreatetime(Date createtime) { 67 this.createtime = createtime; 68 } 69 70 public Date getUpdatetime() { 71 return updatetime; 72 } 73 74 public void setUpdatetime(Date updatetime) { 75 this.updatetime = updatetime; 76 } 77 78 public User() { 79 super(); 80 } 81 82 public User(String username, String password) { 83 super(); 84 this.username = username; 85 this.password = password; 86 } 87 88 }
4.創建訪問數據庫的dao類,在Mybatis中也叫Mapper

package dao; import model.User; public interface UserDao { User getUserByLogin(User user); User getUserByUsername(String username); }
5.根據這個dao類,編寫對應的Mapper.xml,其中,dao類中的方法名稱要和xml中的id對應(至此,model層編寫完畢)

<?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="dao.UserDao" > <!-- namespace為dao類的包路徑 --> <resultMap id="BaseResultMap" type="model.User" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="username" property="username" jdbcType="VARCHAR" /> <result column="password" property="password" jdbcType="VARCHAR" /> <result column="asset" property="asset" jdbcType="REAL" /> <result column="status" property="status" jdbcType="SMALLINT" /> <result column="createtime" property="createtime" jdbcType="TIMESTAMP" /> <result column="updatetime" property="updatetime" jdbcType="TIMESTAMP" /> </resultMap> <!-- 這里的id,入參,返回參數都要和dao類中的方法相對應 --> <select id="getUserByLogin" parameterType="model.User" resultMap="BaseResultMap"> SELECT * FROM USER WHERE username = #{username} and password = #{password} </select> <select id="getUserByUsername" parameterType="java.lang.String" resultMap="BaseResultMap"> select * from user where username = #{username} </select>
6.開始編寫service,其實在這個簡單的項目中可以不必編寫,但是為了規范,還是加個service層(分別是接口和接口實現)

package service; import model.User; public interface UserService { public User getUserByLogin(String username,String password); public User getUserByUsername(String username); }

package service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import dao.UserDao; import model.User; @Service("userService") public class UserServiceImpl implements UserService{ @Autowired private UserDao userDao; @Override public User getUserByLogin(String username, String password) { return userDao.getUserByLogin(new User(username,password)); } @Override public User getUserByUsername(String username) { return userDao.getUserByUsername(username); } }
7.開始編寫Controller層

package controller; import javax.servlet.http.HttpServletRequest; import model.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import service.UserService; import com.alibaba.fastjson.JSONObject; @Controller @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Autowired private HttpServletRequest request; @RequestMapping(value="/login") @ResponseBody public JSONObject login(){ //初始化用到的工具 JSONObject result = new JSONObject(); String msg = ""; int status = 0; //接收ajax傳來的數據 String username = request.getParameter("username"); String password = request.getParameter("password"); //處理業務邏輯(可以看到控制台打出的sql) //select XXXX from user where username=xxx and password = xxx User loginUser = userService.getUserByLogin(username, password); //不為null 的時候說明用戶名和密碼正確 if(loginUser != null) { result.put("loginUserId", loginUser.getId()); status = 1; msg = "Login success!"; }else { msg = "User not exists or wrong password"; } result.put("status", status); result.put("msg", msg); //向前端傳回數據 return result; } }
8.編寫配置文件
jdbc.properties(改成你自己的庫、表,用戶名和密碼)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mytest
jdbc.username=root
jdbc.password=root
validationQuery=SELECT 1

log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
#log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.appender.Console.layout.ConversionPattern=%-5p [%c] - %m%n
log4j.logger.org.apache=INFO
spring-mybatis.xml(spring整合Mybatis)

<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 引入屬性文件 --> <context:property-placeholder location="classpath:jdbc.properties" /> <!-- 配置數據源 com.alibaba.druid --> <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- 初始化連接大小 --> <property name="initialSize" value="0" /> <!-- 連接池最大使用連接數量 --> <property name="maxActive" value="20" /> <!-- 連接池最大空閑 --> <!-- <property name="maxIdle" value="20" /> --> <!-- 連接池最小空閑 --> <property name="minIdle" value="0" /> <!-- 獲取連接最大等待時間 --> <property name="maxWait" value="60000" /> <property name="validationQuery" value="${validationQuery}" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="testWhileIdle" value="true" /> <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- 配置一個連接在池中最小生存的時間,單位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="25200000" /> <!-- 打開removeAbandoned功能 --> <property name="removeAbandoned" value="true" /> <!-- 1800秒,也就是30分鍾 --> <property name="removeAbandonedTimeout" value="1800" /> <!-- 關閉abanded連接時輸出錯誤日志 --> <property name="logAbandoned" value="true" /> <!-- 監控數據庫 --> <!-- <property name="filters" value="stat" /> --> <property name="filters" value="mergeStat" /> </bean> <!-- myBatis文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自動掃描Mapping目錄, 省掉Configuration.xml里的手工配置 --> <property name="mapperLocations" value="classpath:mapping/*.xml" /> </bean> <!-- Spring 和 Mybatis 整合的重要文件,讓spring 去 掃描 mybatis 的映射文件 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> <!-- spring聲明式事務管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 基於注解的事務管理 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
spring-mvc.xml(spring整合springMvc)

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" 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" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 啟用spring mvc 注解--> <mvc:annotation-driven /> <!-- 自動掃描controller包下的所有類,使其認為spring mvc的控制器 --> <context:component-scan base-package="controller" /> <!-- 自動掃描(自動注入) --> <context:component-scan base-package="service" /> <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"> <mvc:message-converters register-defaults="true"> <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> <property name="features"> <value>DisableCircularReferenceDetect,WriteDateUseDateFormat,WriteNullNumberAsZero,WriteNullStringAsEmpty,WriteEnumUsingToString </value> </property> <property name="supportedMediaTypes"> <list> <value>application/json;charset=UTF-8</value> <value>application/xml;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> <value>multipart/form-data;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="favorPathExtension" value="true" /> <property name="favorParameter" value="false" /> <property name="ignoreAcceptHeader" value="true" /> <property name="mediaTypes"> <props> <prop key="json">application/json</prop> <prop key="xml">application/xml</prop> <prop key="html">text/html</prop> </props> </property> </bean> <mvc:default-servlet-handler/> <!-- 視圖解析器:定義跳轉的文件的前后綴 springmvc的,目前沒什么卵用--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/html/" /> <property name="suffix" value=".html" /> </bean> </beans>
web.xml

<?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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <!-- 掃描配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mybatis.xml</param-value> </context-param> <!-- 過濾字符 --> <filter> <description>字符集過濾器</description> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <description>字符集編碼</description> <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> <!-- 監聽器 --> <listener> <description>spring監聽器</description> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 防止spring內存溢出監聽器 --> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <!-- spring mvc servlet --> <servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> <!-- 配置session超時時間,單位分鍾 --> <session-config> <session-timeout>15</session-timeout> </session-config> </web-app>
9.編寫View層(注意引入jquery)

<!DOCTYPE html> <html> <head> <script src="../../js/jquery-3.1.0.min.js"></script> <meta charset="UTF-8"> <title>登錄</title> </head> <body> <h3>用戶登錄</h3> <hr> 用戶名: <input type="text" id="username"/><br> 密碼:<input type="password" id="password"/><br> <input type="button" id="loginBtn" value="登錄"/> <p id="p1"></p> </body> <script> $("#loginBtn").click(function() { if(check()){ login(); }else { $("#p1").html("輸入錯誤!"); } }); //執行登錄操作的函數 function login() { $.ajax({ type:"POST", url:"/user/login.htm", data:{ 'username':$("#username").val(), 'password':$("#password").val() }, dataType:"json", success:function(data) { $("#p1").html("這是后台返回的數據:<br>status:" + data.status + "<br>msg:" + data.msg); }, error:function(data) { $("#p1").html(data.msg); } }); } //前端校驗函數 function check() { var username = $("#username").val(); var password = $("#password").val(); if(!(/^1[3|4|5|7|8]\d{9}$/.test(username)) || password == null || password == "" || password == 0) { return false; } return true; } </script> </html>
此時項目已經算是完成了,我們給項目配上tomcat后啟動項目,訪問 http://localhost:8080/LoginDemo4/html/login.html
此時打開chrome的調試模式(F12),發現居然找不到jquery
這是為什么呢?此時我們再打開 一個地址:
http://localhost:8080/LoginDemo4/js/jquery-3.1.0.min.js 發現居然可以訪問到 jquery的資源。
那么問題就清晰了,我們訪問資源的時候沒有帶上項目名,也就是 LoginDemo4,其實這是jquery ajax異步交互url的問題,我們給的地址是/user/login,說明這是從根目錄進行訪問的,ajax認為的根目錄是http://localhost:8080/,但是我們使用tomcat的時候,它把我們的項目的根目錄變成了http://localhost:8080/LoginDemo4/,所以jquery的地址就變成了http://localhost:8080/LoginDemo4/js/jquery-3.1.0.min.js,但是ajax訪問的地址是http://localhost:8080/js/jquery-3.1.0.min.js,自然就訪問不到了。
那么怎么解決呢?
我首先想到的是,那我們把 ajax的靜態資源的地址前面加上項目名就好了,比如原來的url 是/xxxx/xxxx,就改成/LoginDemo4/xxxx/xxxx,原來的是../../js/jquery.js,就改成../../LoginDemo4/js/jquery.js
事實證明,這是可行的,但是每一個接口都要變,而且這看着很怪異
第二種方法,就是怎么樣讓tomcat把我們的項目根目錄不要帶上項目名
當我們為一個項目配置了tomcat之后,eclipse會多出一個Servers的工程,我們找到對應的tomcat-config文件,里面有個server.xml文件
在該文件的最下面有這么一段
我們把path屬性,改成 "/",就代表項目的根目錄從/LoginDemo4 變成了 /
保存重啟,此時我們看到 jquery 已經成功訪問到了
我們輸入數據庫中的信息
至此,整合成功!(至於mvc架構等知識,由於篇幅有限,作者也沒什么精力,就不寫了。。。)
有問題 歡迎大家留言!