• 基于Maven构建ssh项目


    源码下载:点我


    一、数据库准备

    1.创建数据库maven
    create database maven character set utf8 collate utf8_general_ci; //use maven;

    2.创建用户表

    create table t_users(
    id int primary key auto_increment,
    username varchar(30) not null,
    password varchar(50) not null,
    constraint unq_users_username unique(username)
    );

    3.插入测试数据

    insert into t_users(username,password) values('admin', md5('admin'));
    insert into t_users(username,password) values('user', md5('user'));


    二、项目构建

    1.创建简单Maven项目

    2.在webapps下创建WEB-INF目录,并在WEB-INF下创建web.xml,

    3.复制porm.xml文件内容(jar包的准备)

    4.右击项目-->Maven-->Update Project(解决eclipse报错)

    三、Dao层构建

    1.编写实体类User.java(可以使用Hibernate反向工程)

    package com.hao.entity;

    // Generated 2017-8-6 12:57:28 by Hibernate Tools 4.0.0

    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import static javax.persistence.GenerationType.IDENTITY;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.UniqueConstraint;

    /**
    * TUsers generated by hbm2java
    */
    @Entity
    @Table(name = "t_users", catalog = "maven", uniqueConstraints = @UniqueConstraint(columnNames = "username"))
    public class User implements java.io.Serializable {

    private static final long serialVersionUID = 1L;

    private Integer id;
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
    this.username = username;
    this.password = password;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    public Integer getId() {
    return this.id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    @Column(name = "username", unique = true, nullable = false, length = 30)
    public String getUsername() {
    return this.username;
    }

    public void setUsername(String username) {
    this.username = username;
    }

    @Column(name = "password", nullable = false, length = 50)
    public String getPassword() {
    return this.password;
    }

    public void setPassword(String password) {
    this.password = password;
    }

    }

    2.Dao层代码抽取以及UserDao的编写

    2.1 BaseDao接口

    package com.hao.dao.base;

    import java.io.Serializable;
    import java.util.List;

    public interface BaseDao<T> {

    void save(T entity);
    void delete(T entity);
    void deleteById(Serializable id);
    void update(T entity);
    T findById(Serializable id);
    List<T> findAll();
    }

    2.2 BaseDaoImpl实现类

    package com.hao.dao.base.impl;

    import java.io.Serializable;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;

    import org.hibernate.SessionFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

    import com.hao.dao.base.BaseDao;

    public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {

    private Class<T> entityClass;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {

    //获取子类对象的父类类型
    ParameterizedType superClass = (ParameterizedType) this.getClass().getGenericSuperclass();
    //获得在父类类型上声明的反省数组
    Type[] genericTypes = superClass.getActualTypeArguments();
    //第一个泛型即为实体类型
    entityClass = (Class<T>) genericTypes[0];
    }

    @Override
    public void save(T entity) {
    getHibernateTemplate().save(entity);
    }

    @Override
    public void delete(T entity) {
    getHibernateTemplate().delete(entity);
    }

    @Override
    public void deleteById(Serializable id) {
    T entity = getHibernateTemplate().load(entityClass, id);
    getHibernateTemplate().delete(entity);
    }

    @Override
    public void update(T entity) {
    getHibernateTemplate().update(entity);
    }

    @Override
    public T findById(Serializable id) {
    return getHibernateTemplate().get(entityClass, id);
    }

    @Override
    public List<T> findAll() {
    return getHibernateTemplate().loadAll(entityClass);
    }

    /**
    * HibernateDao接口在使用前必须注入SessionFactory
    * @param sessionFactory
    */
    @Autowired
    public void setSF(SessionFactory sessionFactory){
    super.setSessionFactory(sessionFactory);
    }
    }

    2.3 UserDao接口

    package com.hao.dao;

    import com.hao.dao.base.BaseDao;
    import com.hao.entity.User;

    public interface UserDao extends BaseDao<User>{

    User login(String username, String password);
    }

    2.4 UserDaoImpl实现类

    package com.hao.dao.impl;

    import java.util.List;

    import org.springframework.stereotype.Repository;

    import com.hao.dao.UserDao;
    import com.hao.dao.base.impl.BaseDaoImpl;
    import com.hao.entity.User;

    @Repository("userDao")
    public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao{

    @Override
    public User login(String username, String password) {

    @SuppressWarnings("unchecked")
    List<User> user = (List<User>) getHibernateTemplate().find("from User u where u.username=? and u.password=?", username, password);

    if(user == null || user.size() < 1){
    return null;
    }else{
    return user.get(0);
    }
    }
    }

    2.5 导入MD5工具类,Dao的单元测试和Service层要使用

    package com.hao.utils;

    import java.math.BigInteger;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;

    public class MD5Utils {
    /**
    * 使用md5的算法进行加密
    */
    public static String md5(String plainText) {
    byte[] secretBytes = null;
    try {
    secretBytes = MessageDigest.getInstance("md5").digest(
    plainText.getBytes());
    } catch (NoSuchAlgorithmException e) {
    throw new RuntimeException("没有md5这个算法!");
    }
    String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
    // 如果生成数字未满32位,需要前面补0
    for (int i = 0; i < 32 - md5code.length(); i++) {
    md5code = "0" + md5code;
    }
    return md5code;
    }

    public static void main(String[] args) {
    System.out.println(md5("123"));
    }

    }

    3.注意BaseDao继承的HibernateDaoSupport要选择正确的包,其有分hibernate3,hibernate4和hibernate5,导错包会抛异常

    四、配置spring-dao基础

    1.在applicationContext.xml中配置Spring组件扫描

    <context:component-scan base-package="com.hao"/>

    2.在applicationContext.xml中配置数据源

    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}"/>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
    <property name="user" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
    </bean>

    3.编写db.properties文件,存放在类路径下

    jdbc.jdbcUrl=jdbc:mysql://localhost:3306/maven
    jdbc.driverClass=com.mysql.jdbc.Driver
    jdbc.user=root
    jdbc.password=h66666

    五、Spring整合Hibernate

    1.在applicationContext.xml中配置SessionFactory,注意class属性也要选择正确的包

    <!-- 加载配置方案2:在spring配置中放置hibernate配置信息 -->
    <bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
    <!-- 将连接池注入到sessionFactory, hibernate会通过连接池获得连接 -->
    <property name="dataSource" ref="dataSource" ></property>
    <!-- 配置hibernate基本信息 -->
    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.show_sql" >true</prop>
    <prop key="hibernate.format_sql" >true</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>

    </props>
    </property>
    <!-- 引入orm元数据,指定orm元数据所在的包路径,spring会自动读取包中的所有配置 -->
    <property name="packagesToScan" value="com.hao.entity"></property>
    </bean>

    2.在applicationContext.xml中配置核心事务管理器

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    3.开启注解事务(也可以使用声明式事务)

    <tx:annotation-driven transaction-manager="transactionManager" />

    4.由于我采用注解定义Hibernate实体类,因此映射注解元数据使用的是packagesToScan属性

    <property name="packagesToScan" value="com.hao.entity"></property>

    5.如果使用的是hbm.xml文件映射元数据,可以使用mappingLocations(建议)或mappingDirectoryLocations

    <property name="mappingLocations" value="classpath:com/hao/entity/*.hbm.xml"></property>

    六、配置log4j日志环境

    以下为log4j.properties的内容:

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.out
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

    log4j.appender.file=org.apache.log4j.FileAppender
    log4j.appender.file.File=D:\temp\mylog.log
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

    ### fatal error warn info debug debug trace
    log4j.rootLogger=debug, stdout
    #log4j.logger.org.hibernate=INFO
    #log4j.logger.org.hibernate.type=INFO


    七、DAO层单元测试

    1.注意,由于Spring的事务配置Service层,因此Dao层不具有事务性,因此单元测试必须添加@Transactional注解
    2.经过测试,dao层的单元测试默认会执行事务回滚(不知为何,可能是因为没有配置@Transaction注解的参数?)
    3.若想要不进行回滚而在数据库看到结果(如插入等),需添加@Rollback(false)
    4.UserDao的测试代码

    package com.hao.dao;

    import junit.framework.Assert;

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.annotation.Rollback;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.transaction.annotation.Transactional;

    import com.hao.entity.User;
    import com.hao.utils.MD5Utils;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:applicationContext.xml"})
    @Transactional
    @Rollback(false)
    public class UserDaoTest {

    @Autowired
    UserDao userDao;

    @Test
    public void testLogin(){

    Assert.assertNotNull(userDao.login("admin", MD5Utils.md5("admin")));
    Assert.assertNull(userDao.login("admin", MD5Utils.md5("pass")));
    Assert.assertNotNull(userDao.login("user", MD5Utils.md5("user")));

    }

    @Test
    public void testSave(){
    User u = new User();
    u.setUsername("dao");
    u.setPassword("dao");
    userDao.save(u);
    }

    }

    八、编写Service层代码

    1.UserService接口

    package com.hao.service;

    import com.hao.entity.User;

    public interface UserService {

    User login(User user);

    void save(User user);

    }


    2.UserServiceImpl实现类,要求使用注解配置事务

    package com.hao.service.impl;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;

    import com.hao.dao.UserDao;
    import com.hao.entity.User;
    import com.hao.service.UserService;
    import com.hao.utils.MD5Utils;

    @Service("userService")
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = true)
    public class UserServiceImpl implements UserService{

    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }

    @Override
    public User login(User user) {
    String pass = MD5Utils.md5(user.getPassword());
    return userDao.login(user.getUsername(), pass);
    }

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = false)
    public void save(User user) {
    userDao.save(user);
    }
    }


    九、编写Service层的单元测试

    1.由于Service配置了Spring的事务,因此基于Service的单元测试无需再添加@Transactional注解
    2.经测试,Service层的单元测试默认不具有回滚性(可能与@Transaction注解有关)
    3.并且,即使在测试类上添加注解@rollback(true)注解也无法回滚(不知原因)
    4.UserService测试代码

    package com.hao.service;

    import junit.framework.Assert;

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.annotation.Rollback;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    import com.hao.entity.User;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    @Rollback(true)
    public class UserServiceTest {

    @Autowired
    UserService userService;

    @Test
    public void testLogin(){

    User u1 = new User();
    u1.setUsername("admin");
    u1.setPassword("admin");

    User u2 = new User();
    u2.setUsername("admin");
    u2.setPassword("pass");

    User u3 = new User();
    u3.setUsername("user");
    u3.setPassword("user");

    Assert.assertNotNull(userService.login(u1));
    Assert.assertNull(userService.login(u2));
    Assert.assertNotNull(userService.login(u3));
    }

    @Test
    public void testSave(){

    User u = new User();
    u.setUsername("service");
    u.setPassword("service");

    userService.save(u);

    }

    }

    十、Action层的抽取以及编写UserAction

    1.抽取BaseAction

    package com.hao.action.base;

    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Map;

    import org.apache.struts2.interceptor.RequestAware;
    import org.apache.struts2.interceptor.SessionAware;

    import com.opensymphony.xwork2.ActionSupport;
    import com.opensymphony.xwork2.ModelDriven;

    public class BaseAction<T> extends ActionSupport implements ModelDriven<T>, RequestAware, SessionAware{

    private static final long serialVersionUID = 1L;

    protected Map<String, Object> request;
    protected Map<String, Object> session;
    protected T model;

    @Override
    public void setRequest(Map<String, Object> request) {
    this.request = request;
    }

    @Override
    public void setSession(Map<String, Object> session) {
    this.session = session;
    }

    @Override
    public T getModel() {
    return model;
    }

    public BaseAction() {

    //获取父类
    ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
    //获取父类的泛型数组
    Type[] types = genericSuperclass.getActualTypeArguments();
    //取得第一个泛型,即Model的类型
    @SuppressWarnings("unchecked")
    Class<T> entityClass = (Class<T>) types[0];
    try {
    model = entityClass.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
    throw new RuntimeException(e);
    }
    }

    }

    2.UserAction代码编码,继承于BaseAction

    package com.hao.action;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Controller;

    import com.hao.action.base.BaseAction;
    import com.hao.entity.User;
    import com.hao.service.UserService;

    @Controller("userAction")
    @Scope("prototype")
    public class UserAction extends BaseAction<User>{

    private static final long serialVersionUID = 1L;

    public String login(){
    System.out.println("-------------------------------------------------------"+this);
    User user = userService.login(model);
    if(user == null){
    request.put("errorInfo", "用户名或密码错误");
    return LOGIN;
    }
    session.put("loginUser", user);
    return SUCCESS;
    }

    @Autowired
    private UserService userService;

    public UserService getUserService() {
    return userService;
    }

    public void setUserService(UserService userService) {
    this.userService = userService;
    }

    }


    十一、配置struts2,并整合到Spring

    1.在web.xml中配置struts2过滤器

    <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    2.配置struts.xml,其中Action的类名写成Spring中定义的实体名(Spring与Struts2的整合)

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

    <struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.objectFactory" value="spring" />

    <package name="hao" namespace="/" extends="struts-default">
    <action name="userAction_*" class="userAction" method="{1}">
    <result>/success.jsp</result>
    <result name="login">/index.jsp</result>
    </action>
    </package>

    </struts>

    3.注意将struts2整合到Spring时,Action的scope必须为prototype,采用bean的prototy属性或者@Scope注解进行配置
    4.为什么必须是prototype?这是由struts2的架构所决定的!

    十二、(可选)如果Action是以解耦方式编写的(即不依赖容器产生HttpServletRequest和HttpServletResponse),还可以对Action层进行单元测试

    1.对Action层做单元测试相当于模拟一次请求而进行对应的方法调用
    2.对Action进行单元测试的前提是,在对Action进行编码时,采用解耦方式获取request,response,session等(即拿到的是一个Map),这样就不需要Servlet便可以执行测试
    3.UserAction测试代码

    package com.hao.action;

    import java.util.HashMap;
    import java.util.Map;

    import junit.framework.Assert;

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationCOntext.xml")
    public class UserActionTest {

    @Autowired
    UserAction userAction;

    @Before
    public void init(){
    //模拟容器,提供Request和Session
    Map<String, Object> request = new HashMap<String, Object>();
    Map<String, Object> session = new HashMap<String, Object>();
    userAction.setRequest(request);
    userAction.setSession(session);
    }

    @Test
    public void testLogin(){

    //模拟提供请求参数
    userAction.getModel().setUsername("admin");
    userAction.getModel().setPassword("admin");
    //模拟一次登录请求
    Assert.assertEquals(UserAction.SUCCESS, userAction.login());

    //模拟提供请求参数
    userAction.getModel().setUsername("admin");
    userAction.getModel().setPassword("pass");
    //模拟错误的用户名密码登录请求
    Assert.assertEquals(UserAction.LOGIN, userAction.login());
    }

    }

    十三、Spring整合到Web环境

    1.在web.xml配置Spring上下文随Web上下文启动而启动

    <!-- 配置spring框架的监听器 -->
    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 通过上下文参数指定spring配置文件位置 -->
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    2.扩展Session的作用域到请求结束(web.xml),注意选择正确的Hibernate版本,而且注意要配置在struts2过滤器之前

    <!-- 配置过滤器,解决hibernate延迟加载问题 -->
    <filter>
    <filter-name>openSessionInView</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>openSessionInView</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    十四、编写页面,启动项目

    1.编写index.jsp,注意引入jstl标签库

    <body>

    <form action="userAction_login.action" method="post">
    <span>用户名:</span><input type="text" name="username"/><br/>
    <span>密 码:</span><input type="password" name="password"/><br/>
    <input type="submit" value="提交"/>
    </form>
    <c:if test="${not empty requestScope.errorInfo }">
    <c:out value="${errorInfo }"/>
    </c:if>
    </body>

    2.编写success.jsp

    <h5>${sessionScope.loginUser.username }登陆成功</h5><hr/>

    3.启动项目,访问index.jsp观察结果


  • 相关阅读:
    [面试题]什么是面向对象编程
    面向对象编程的新手理解
    Object of type type is not JSON serializable
    STL---map
    STL---llist
    Div标签使用inline-block有间距
    STL---vector
    KMP算法
    算法06
    算法05
  • 原文地址:https://www.cnblogs.com/tommychok/p/7340500.html
Copyright © 2020-2023  润新知