一、目的:
使初学者能更好的去了解SSH框架。给以后的自己,也给别人一个参考。尝试搭建一个完整的SSH框架项目。二、SSH三大框架的概述
Struts + Spring + Hibernate三者各自的特点都是什么?
Struts 的MVC设计模式可以使我们的逻辑变得很清晰,主要负责表示层的显示。
Spring 的IOC和AOP可以使我们的项目在最大限度上解藕。
hibernate的就是实体对象的持久化了, 数据库的封装。
表现层、中间层(业务逻辑层)和数据服务层。三层体系将业务规则、数据访问及合法性校验等工作放在中间层处理。客户端不直接与数据库交互,而是通过组件与中间层建立连接,再由中间层与数据库交互。
表现层是传统的JSP技术。
中间层采用的是流行的Spring+Hibernate,为了将控制层与业务逻辑层分离,又细分为以下几种。
Web层,就是MVC模式里面的“C”(controller<action>),负责控制业务逻辑层与表现层的交互,调用业务逻辑层,并将业务数据返回给表现层作组织表现,该系统的MVC框架采用Struts。
Service层(就是业务逻辑层),负责实现业务逻辑。业务逻辑层以DAO层为基础,通过对DAO组件的正面模式包装,完成系统所要求的业务逻辑。
DAO层,负责与持久化对象交互。该层封装了数据的增、删、查、改的操作。
PO,持久化对象。通过实体关系映射工具将关系型数据库的数据映射成对象,很方便地实现以面向对象方式操作数据库。
Spring的作用贯穿了整个中间层,将Web层、Service层、DAO层及PO无缝整合,其数据服务层用来存放数据。
三、项目实战案例
创建项目有两种方式:web动态项目及maven项目(建议使用maven创建项目)。
创建web动态工程注意classpath路径
导入本次项目要使用到的jar包:
struts:http://struts.apache.org/
hibernate:https://sourceforge.net/projects/hibernate/files/latest/download?source=files (访问就提示下载,无需做其它操作)
spring:http://maven.springframework.org/release/org/springframework/spring/
在lib文件夹下添加相关jar包依赖(建议使用maven创建项目,便于jar包管理,避免jar版本冲突)
相关配置文件:
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" 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"> <display-name>ssh</display-name> <!-- 将Spring配置到web项目中 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 将struts配置到web项目中 --> <filter> <filter-name>struts</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" 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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 在实际开发中通常都需配置 mvc:annotation-driven标签,这个标签是开启注解 --> <mvc:annotation-driven/> <mvc:default-servlet-handler/> <!-- 开启文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <!-- 指定哪些包下经过controller --> <context:component-scan base-package="com.blog.admin.controller,com.blog.blog.controller"></context:component-scan> <!-- 视图解析器ViewResolver --> <!-- 解析jsp,默认支持jstl prefix:前缀, suffix:后缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
<!-- 自动处理静态资源文件 --> <mvc:default-servlet-handler /> <!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*" /> <bean class="com.blog.admin.interceptor.TestInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- context 注解 --> <!-- tx 事务--> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 开启注解 --> <context:annotation-config/> <!-- 指定哪些包下受baen管制 --> <context:component-scan base-package="com.blog"></context:component-scan> <!-- 数据源(数据库) --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mariadb://localhost:3300/blog"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!-- 配置SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <!-- 扩展使用Hibernate原生的配置 --> <property name="hibernateProperties"> <props> <prop key="dialect">org.hibernate.dialect.MariaDB53Dialect</prop> <prop key="show_sql">true</prop> </props> </property> <!-- 映射实体类(Entity) --> <property name="packagesToScan" value="com.blog.blog.entity, com.blog.admin.entity"/> </bean> <!-- 事务层 --> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 事务注解 --> <tx:annotation-driven/> <!-- 开启aop --> <aop:aspectj-autoproxy/> </beans>struts.xml
<?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> <package namespace="/" name="default" extends="struts-default"> <!-- 设置和配置action的拦截器 --> <interceptors> <interceptor name="loginInterceptor" class="com.blogAdmin.action.articleTpye.LoginInterceptorAction"></interceptor> </interceptors> <!-- 定义为全局结果,这样action和result都能访问 --> <global-results> <result name="loginRedirect" type="redirectAction">loginPage</result> </global-results> <!-- 登陆成功跳转的页面 --> <action name="list" class="com.blogAdmin.action.articleTpye.ListAction"> <interceptor-ref name="defaultStack"></interceptor-ref> <!-- 系统默认拦截器 --> <interceptor-ref name="loginInterceptor"></interceptor-ref> <!-- 自己定义的拦截器 --> <!-- 首页面 --> <result name="list">/WEB-INF/jsp/articleType/list.jsp</result> </action> </package> </struts>后台代码(部分,不完整)
Entity层(具体根据数据库表及字段进行创建相应实体类)
初始化Hibernate的entity
package com.blogAdmin.init; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.hibernate.SessionFactory; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; public class HibernateInit extends HttpServlet { private static final long serialVersionUID = 1L; public static SessionFactory sf; @Override public void init() throws ServletException { super.init(); final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build(); sf = new MetadataSources(registry).buildMetadata().buildSessionFactory(); } }dao层
userDao类
package com.blogAdmin.dao; import java.io.Serializable; import org.hibernate.Session; import org.hibernate.query.Query; import com.opensymphony.xwork2.ActionSupport; import com.blogAdmin.entity.Article; import com.blogAdmin.entity.User; import com.blogAdmin.init.HibernateInit; /** * 用户登陆的dao * @author admin * */ public class UserDao extends ActionSupport implements Serializable { private static final long serialVersionUID = -9124089639234157594L; public User findByUserName(String username){ Session session = HibernateInit.sf.openSession(); String hql = "from User where username=?"; Query<User> dbUser = session.createQuery(hql,User.class); dbUser.setParameter(0, username); return dbUser.uniqueResult(); } public Article getByUser(String id){ Article article = null; Session session = HibernateInit.sf.openSession(); article = session.get(Article.class, id); session.close(); return article; } }(增删改查)dao层
package com.blogAdmin.dao; import java.math.BigInteger; import java.util.List; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.query.Query; import com.blogAdmin.entity.Article; import com.blogAdmin.init.HibernateInit; import com.blogAdmin.vo.ArticleVo; public class ArticleDao { /** * 添加 * @param article */ public void save(Article article) { Session session = HibernateInit.sf.openSession(); Transaction ts = session.beginTransaction(); session.save(article); ts.commit(); session.close(); } /** * 删除 * @param id */ public void delete(String id) { Session session = HibernateInit.sf.openSession(); Transaction ts = session.beginTransaction(); String hql = "delete from Article where id=?"; session.createQuery(hql).setParameter(0, id).executeUpdate(); ts.commit(); session.close(); } /** * 修改 * @param article */ public void update(Article article) { Session session = HibernateInit.sf.openSession(); Transaction ts = session.beginTransaction(); session.update(article); ts.commit(); session.close(); } /** * 分页查询 * @param pageNum * @param pageSize * @return */ public List<ArticleVo> pageList(int pageNum, int pageSize) { List<ArticleVo> returnList = null; Session session = HibernateInit.sf.openSession(); Query<ArticleVo> query = session.createNativeQuery("select a.*,u.username name,t.name articleType from article a join user u join article_type t on a.user_id=u.id and a.type_id=t.id order by a.create_time",ArticleVo.class); query.setFirstResult((pageNum - 1) * pageSize); query.setMaxResults(pageSize); returnList = query.list(); session.close(); return returnList; } /** * 获取总条数 * @return */ public BigInteger totalCount() { BigInteger totalCount = new BigInteger("0"); Session session = HibernateInit.sf.openSession(); totalCount = (BigInteger) session.createNativeQuery("select count(id) from article").uniqueResult(); session.close(); return totalCount; } /** * 根据id查询一条数据 * @param typeId * @return */ public Article getById(String id){ Article article = null; Session session = HibernateInit.sf.openSession(); article = session.get(Article.class, id); session.close(); return article; } }service<接口>及serviceImpl<实现类>层
略
action层
LoginAction类
package com.blogAdmin.action.articleTpye; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import org.apache.struts2.interceptor.ServletRequestAware; import com.opensymphony.xwork2.ActionSupport; import com.blogAdmin.dao.UserDao; import com.blogAdmin.entity.User; import com.blogAdmin.vo.UserVo; /** * 登陆页面的action * @author admin * */ @Results({@Result(location="/WEB-INF/jsp/login.jsp"), @Result(name="list",type="redirectAction",location="list"), @Result(name="loginPage",type="redirectAction",location="loginPage")}) public class LoginAction extends ActionSupport implements ServletRequestAware{ private static final long serialVersionUID = 6690219852711831094L; private HttpSession session; //获取session对象,将UserVo对象存入session private UserVo userVo; public UserVo getUserVo() { return userVo; } public void setUserVo(UserVo userVo) { this.userVo = userVo; } /** * 1,打开登陆页面 */ @Action("/loginPage") public String loginPage() { return SUCCESS; } /** *2,登陆按钮action * @return */ @Action("/login") public String login(){ //判断是否为空 String name = userVo.getUsername(); String pass = userVo.getPassword(); if(name==null||"".equals(name)&&pass==null||"".equals(pass)){ session.setAttribute("msg", "用户名或密码不能为空!"); return "loginPage"; } UserDao dao = new UserDao(); User user = dao.findByUserName(userVo.getUsername()); if(user==null){ session.setAttribute("msg", "用户名或密码不正确!"); return "loginPage"; } if (!user.getPassword().equals(pass)) { session.setAttribute("msg", "用户名或密码不正确!"); return "loginPage"; } session.setAttribute("userVo", userVo); return "list"; } @Override public void setServletRequest(HttpServletRequest request) { this.session = request.getSession(); } }LoginInterceptorAction类
package com.blogAdmin.action.articleTpye; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class LoginInterceptorAction implements Interceptor{ private static final long serialVersionUID = -7254285326542480257L; @Override public void destroy() { } @Override public void init() { } @Override public String intercept(ActionInvocation invocation) throws Exception { HttpSession session = ServletActionContext.getRequest().getSession(); //通过struts的上下文,获取到session对象 Object userVo = session.getAttribute("userVo"); if (userVo==null) { return "loginRedirect"; //如果为空,重定向到login页面; } return invocation.invoke(); } }PageAction相关类
package com.blogAdmin.action.articleTpye; import org.apache.struts2.ServletActionContext; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import com.opensymphony.xwork2.ActionSupport; import com.blogAdmin.dao.ArticleTypeDao; import com.blogAdmin.entity.ArticleType; @Results({ @Result(name = "typeSave", location = "/WEB-INF/jsp/articleType/save.jsp"), @Result(name="updateType", location = "/WEB-INF/jsp/articleType/update.jsp"), @Result(name="redirectTypeSave",type="redirectAction",location="typeSave"), @Result(name="redirectList",type="redirectAction",location="list"), @Result(name = "list", location = "/WEB-INF/jsp/articleType/list.jsp") }) public class ArticleTypeAction extends ActionSupport { private static final long serialVersionUID = 6780775618333937202L; //添加 private String typeName; //分页 private int pageNum; private int pageSize=10; //删除 private String typeId; //修改时的对象 ArticleType articleType; /** * 文章列表 * @return */ @Action("/articleType/list") public String list(){ ArticleTypeDao dao = new ArticleTypeDao(); ServletActionContext.getRequest().setAttribute("list", dao.pageList(pageNum, pageSize)); ServletActionContext.getRequest().setAttribute("totalCount", dao.totalCount()); return "list"; } /** * 进入添加页面 * @return */ @Action("/articleType/typeSave") public String typeSave() { return "typeSave"; } /** * 点击保存(添加分类) * @return */ @Action("/articleType/save") public String save() { ArticleTypeDao dao = new ArticleTypeDao(); dao.save(typeName); return "redirectList"; } /** * 删除页面 * @return */ @Action("/articleType/delete") public void delete(){ ArticleTypeDao dao = new ArticleTypeDao(); dao.delete(typeId); } /** * 进入编辑页面 * @return */ @Action("/articleType/updateType") public String updateType(){ ArticleTypeDao dao = new ArticleTypeDao(); ServletActionContext.getRequest().setAttribute("articleType", dao.getById(typeId)); return "updateType"; } /** * 点击修改 * @return */ @Action("/articleType/update") public String update() { ArticleTypeDao dao = new ArticleTypeDao(); dao.update(articleType); return "redirectList"; } public String getTypeName() { return typeName; } public void setTypeName(String typeName) { this.typeName = typeName; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public String getTypeId() { return typeId; } public void setTypeId(String typeId) { this.typeId = typeId; } public ArticleType getArticleType() { return articleType; } public void setArticleType(ArticleType articleType) { this.articleType = articleType; } }IndexAction类
package com.blogAdmin.action.articleTpye; import com.opensymphony.xwork2.ActionSupport; /** * 登陆成功后展示的页面 * @author admin * */ public class ListAction extends ActionSupport{ private static final long serialVersionUID = -7248676355265672252L; /** * 首页面 * @return */ @Override public String execute() throws Exception { return "list"; } }