初学java EE,虽然知道使用框架会使开发更加便捷高效,但是对于初学者来说,感到使用框架比较迷惑,尤其是各种jar包的引用、各种框架的配置、注解的使用等等。
最好的学习方法就是实践,于是下载了一个现成的DEMO,通过简单的修改先成功在自己电脑上跑起来,然后再逐个文件进行分析学习,最终才能从总体的高度上掌握框架的运行机制和配置方法,这样才能在实际运用中灵活配置,不会再局限于示例框架中。
SSM框架搭建流程
上面链接总结的流程很好,但是该流程没有加入DAO这一层,经过分析本项目源码,流程应该是这样的:
database–>Entity.java–>mapper.xml–>Mapper.java–>Dao.java–>DaoImpl.java–>Service.java–>ServiceImpl.java–>Controller.java–>login.jsp
- 根据需要建立数据库、数据表、字段;
- 根据表中字段建立实体类;
- 在Mapper中实现对数据库的增删改查操作;
- 设计DAO(data access object)数据操作对象接口;
- 设计Service,通过DAO获取对象,然后进行业务逻辑实现;
- 设计控制层Controller,用于从页面获取请求,调用Service处理并将处理结果返回给页面。
根据上面所列,下面就按照这个流程进行设计。
数据库设计
使用MySQL数据库:
- 建立数据库 DB_TEST
CREATE DATABASE DB_TEST;
- 1
- 建立用户表 T_USER
CREATE TABLE T_USER ( ID INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, USERNAME VARCHAR(16) NOT NULL, PASSWORD VARCHAR(16) NOT NULL );
- 1
- 2
- 3
- 4
- 5
- 插入一条用户信息
INSERT INTO T_USER (USERNAME,PASSWORD) VALUES ("admin","123");
- 1
建立USER实体类
public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int 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; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
Mapper实现增删改查
- UserMapper接口,定义通过用户名获取用户对象的方法
public interface UserMapper { public User getUserByName(String username); }
- 1
- 2
- 3
- 4
- usermapper.xml,用于操作数据库,实现接口中的方法
<mapper namespace="com.crm.mapper.UserMapper"> <resultMap type="com.crm.entity.User" id="userMap"> <id property="id" column="id" /> <result property="username" column="username" /> <result property="password" column="password" /> </resultMap> <!-- 此处select标签的id值对应Mapper类中方法名 --> <select id="getUserByName" parameterType="string" resultMap="userMap"> <!-- 此处写sql语句,#{Mapper类传入的参数} --> select * from T_USER where username = #{username} </select> </mapper>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
DAO 数据操作对象
- DAO接口 UserDao.java
public interface UserDao { //接口方法,通过用户名得到User对象 public User findUserByName(String username); }
- 1
- 2
- 3
- 4
- DAO接口实现 UserDaoImpl.java
@Repository对应数据访问层Bean
@Repository(value=”userDao”)注解是告诉Spring,让Spring创建一个名字叫“userDao”的UserDaoImpl实例。
当Service需要使用Spring创建的名为“userDao”的UserDaoImpl实例时, 就可以使用@Resource(name =”userDao”)注解告诉Spring,Spring把创建好的userDao注入给Service即可。
@Repository("userDao") public class UserDaoImpl implements UserDao { //注解引用Mapper类资源 @Resource(name = "userMapper") private UserMapper userMapper; /* 根据用户名查找用户对象 */ public User findUserByName(String username) { //调用Mapper类从数据库中得到User对象 return userMapper.getUserByName(username); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
业务层 Service
- 业务层接口 UserService.java
public interface UserService { // 通过用户名及密码核查用户登录 public User checkLogin(String username, String password); }
- 1
- 2
- 3
- 4
- 业务层接口实现类 UserServiceImpl.java
@Service对应的是业务层Bean
这样当Action需要使用UserServiceImpl的的实例时,就可以由Spring创建好的”userService”注入给Action:在Action只需要声明一个名字叫“userService”的变量来接收由Spring注入的”userService”即可
@Service("userService") public class UserServiceImpl implements UserService { @Resource private UserDao userDao; /* 登陆验证 */ public User checkLogin(String username, String password) { //根据用户名实例化用户对象 User user = userDao.findUserByName(username); if (user != null && user.getPassword().equals(password)) { return user; } return null; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
控制层 Controller
@Controller对应表现层的Bean,也就是Action
注意:如果@Controller不指定其value【@Controller】,则默认的bean名字为这个类的类名首字母小写,如果指定value【@Controller(value=”UserAction”)】或者【@Controller(“UserAction”)】,则使用value作为bean的名字。
@Scope(“prototype”)表示将Action的范围声明为原型
可以利用容器的scope=”prototype”来保证每一个请求有一个单独的Action来处理,避免struts中Action的线程安全问题。
spring 默认scope 是单例模式(scope=”singleton”),这样只会创建一个Action对象,每次访问都是同一Action对象,数据不安全。
struts2 是要求每次次访问都对应不同的Action,scope=”prototype” 可以保证当有请求的时候都创建一个Action对象
@RequestMapping(“/user”)
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
本项目中,该Controller类RequestMapping(”user”) 该Controller类的login方法RequestMapping(”login”) 所以登录页面中用户登录的 action=”/ssm/user/login”
@Controller @Scope(value="prototype") @RequestMapping("/user") public class UserController { @Resource private UserService userService; @RequestMapping(value="/login",method=RequestMethod.POST) public String login(User user,Model model) throws Exception { user=userService.checkLogin(user.getUsername(), user.getPassword()); if(user!=null){ model.addAttribute(user); return "welcome";// 路径 WEB-INF/pages/welcome.jsp } return "fail"; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
页面 JSP
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>用户登录</title> </head> <body> <form action="/ssm/user/login" method="post" id="myform"> <input type="text" id="username" name="username"/> <input type="password" id="password" name="password"/> <input type="submit" value="提交" id="login" /> </form> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
DEMO工程中的所有配置文件
applicationContext.xml
这个文件是Spring公共配置文件,下面分块进行解析。
- 数据库配置文件database.properties的引入
<bean id="property" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <!-- classpath 即src根目录 --> <value>classpath:database.properties</value> </list> </property> </bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 数据库连接池的配置
数据库连接池可以让服务器预先与数据库建立部分连接,存入内存中,以减少连接数据库的耗时操作。 此处定义使用C3P0连接池的数据源。
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- 指定连接数据库的JDBC驱动 --> <property name="driverClass"> <value>${mysql.driver_class}</value> </property> <!-- 连接数据库所用的URL --> <property name="jdbcUrl"> <value>${mysql.connection.url}</value> </property> <!-- 连接数据库的用户名 --> <property name="user"> <value>${mysql.connection.username}</value> </property> <!-- 连接数据库的密码 --> <property name="password"> <value>${mysql.connection.password}</value> </property> <!-- 设置数据库连接池的最大连接数 --> <property name="maxPoolSize"> <value>30</value> </property> <!-- 设置数据库连接池的最小连接数 --> <property name="minPoolSize"> <value>2</value> </property> <!-- 设置数据库连接池的初始化连接数 --> <property name="initialPoolSize"> <value>2</value> </property> <!-- 设置数据库连接池的连接的最大空闲时间,单位为秒 --> <property name="maxIdleTime"> <value>10</value> </property> </bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 自动扫描配置
使用< context:component-scan>标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean
<context:component-scan base-package="com.crm.*"> <!-- 不扫描注解为controller的类型 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
- 1
- 2
- 3
- 4
- 集成Mybatis
SqlSessionFactoryBean是一个工厂bean,它的作用就是解析配置(数据源、别名等)。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 引用上面已经配置好的数据库连接池 --> <property name="dataSource" ref="dataSource" /> <!-- Mybatis的配置文件路径 --> <property name="configLocation" value="classpath:mybatis.xml" /> <!-- mapper配置路径 --> <property name="mapperLocations"> <list> <value>classpath:com/crm/mapper/*.xml</value> </list> </property> </bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- Mapper扫描配置
dao需要配置,如果数量大不适合一个个配置,需要使用mapper自动扫描来批量进行配置。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.crm.mapper" /> </bean>
- 1
- 2
- 3
- Mybatis事务管理配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
- 1
- 2
- 3
- 4
数据库配置文件database.properties
mysql.driver_class=com.mysql.jdbc.Driver
<!-- DB_TEST为新建的数据库名 --> mysql.connection.url=jdbc:mysql://localhost:3306/DB_TEST <!-- 登录数据库的用户名密码 --> mysql.connection.username=root mysql.connection.password=root
- 1
- 2
- 3
- 4
- 5
- 6
日志管理文件 log4j.properties
此处省略,入门阶段暂不考虑这么高端的日志用法。
Mybatis配置文件
通过使用别名,可以缩短类名的长度,但是只能在配置文件中使用。
<configuration> <!-- 别名 --> <typeAliases> <typeAlias type="com.crm.entity.User" alias="user" /> </typeAliases> </configuration>
- 1
- 2
- 3
- 4
- 5
- 6
web配置文件
此配置文件注释比较清楚,就不单独解析了。
<display-name>crm</display-name> <!--一个server下如果有多个项目,要对webAppRootKey进行配置,让log能将日志写到对应项目根目录下--> <context-param> <param-name>webAppRootKey</param-name> <param-value>crm.root</param-value> </context-param> <!-- 由Sprng载入的Log4j配置文件位置 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.properties</param-value> </context-param> <!-- Spring默认刷新Log4j配置文件的间隔,单位为millisecond --> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>60000</param-value> </context-param> <!-- Web 项目 Spring 加载 Log4j 的监听 --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!-- 设置Spring容器加载配置文件路径 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:springContext/*Context.xml</param-value> </context-param> <!-- 加载Spring容器配置 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 防止内存泄漏的监听器 --> <listener> <listener-class> org.springframework.web.util.IntrospectorCleanupListener </listener-class> </listener> <!-- 配置Springmvc核心控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/springmvc.xml</param-value> </init-param> <!-- 立马启动servlet --> <load-on-startup>1</load-on-startup> </servlet> <!-- servlet-mapping配置 --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 解决工程编码过滤器 --> <filter> <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 设置默认打开页面列表 --> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list> </web-app>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
springmvc配置文件
之前扫描专门忽略了Controller,在此处扫描。
例如在Controller类中常有类似
return welcome
这样的语句其实完整的应该是
return WEB-INF/pages/welcome.jsp
<!-- 注解Controller扫描器 --> <context:component-scan base-package="com.crm.controller"/> <!-- 静态资源访问 --> <mvc:resources location="/img/" mapping="/img/**"/> <mvc:resources location="/js/" mapping="/js/**"/> <mvc:resources location="/common/" mapping="/common/**"/> <!-- 注解功能的默认配置,处理器和映射器 --> <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> <bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> <!-- 前后缀配置 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
至此基本内容已经全部完了,项目可以轻松跑起来了。
但是在学习过程中,发现这些框架真的是太强大了,不知道什么时候才能掌握更多,目前仅仅是会用最基本的皮毛而已。
笔耕不缀,必有收获;代码不停,早晚能行。