之前的《图书信息管理系统》项目中(http://blog.csdn.net/ssh159/article/details/52439676),
Spring的配置太繁琐。考虑开发大项目上,假设项目的action层会有成百上千 个Class类,不简化代码的
情况下就要在Spring的配置中装配上千个actionClass的<bean>,applicationContext.xml的代码太多了。
@H_301_44@1、使用注解 代替applicationContext.xml中的 <bean> 标签,添加 注解扫描器,解析器。
@H_301_44@简化 xml处的配置信息。
@H_301_44@2、使用Aop,只保留事务处理的代码(只保留核心关注点和横切关注点),删掉多余的动作;
@H_301_44@(这是面向切面的知识,不懂可以看看我之前写的
@H_301_44@【java初学者】理解,从面向过程 到 面向对象,面向接口,面向切面例子。)
@H_301_44@(之前的博客:【JAVA】理解MVC模式,IOC,AOP,orm框架,SOA,ERP管理系统
@H_301_44@AOP:将应用程序中的商业逻辑及对其提供支持的 应用服务 进行分离。
@H_301_44@商业逻辑:
@H_301_44@ 核心关注点(主要是带入对象和对象的特殊事务),
@H_301_44@ 横切关注点(经常发生在核心关注点的各处,各处都基本相似,用以:权限认证,日志,事务处理)。
@H_301_44@通用服务:做记录,日记。@H_301_44@)
@H_301_44@
@H_301_44@之前的写法:
@H_301_44@因为不想new 对象,所以在application中,
@H_301_44@1、一个类和2个接口@H_301_44@(IndexAction,IndexServiceImpl,IndexDaoImpl)都要标明非单例;
@H_301_44@2、用<bean> <prototype>标签 取代那些私有属性(is,id,sessionFactory)new对象;
3、私有属性(is,sessionFactory)还要设置属性和方法;
@H_301_44@
IndexAction 控制层的代码:
@H_301_44@
private IndexService is = null; public void setIs(IndexService is) { this.is = is;
IndexServiceImpl 业务逻辑处理层接口 的代码:
@H_301_44@
private IndexDao id; //用于注入使用 public void setId(IndexDao id) { System.out.println("有人给我注入了一个dao实例:"+id); this.id = id; }
@H_301_44@
private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sf) { this.sessionFactory = sf; }
applicationContext.xml中的代码
<bean id="myIndexAction" class="ssh.action.IndexAction" scope="prototype"> <!-- setIs(myIndexService) --> <property name="is" ref="myIndexService"/> </bean> <!-- myIndexService = new ssh.service.IndexServiceImpl() --> <bean id="myIndexService" class="ssh.service.IndexServiceImpl" scope="prototype"> <property name="id" ref="myIndexDao"/> </bean> <bean id="myIndexDao" class="ssh.dao.IndexDaoImpl" scope="prototype"> <!-- 晚点再注入能用的seesionFactory --> <property name="sessionFactory" ref="mySessionFactory"></property> </bean>
现在解决方案:
@H_301_44@1、 在项目中加入注解:
让Spring自动的为Class类定义的属性装配bean以及让Spring自动的扫描程序包中的类,隐式的在配置文件中
添加Class类的bean。
注解分为两种,一是类的注解,二是类中属性的注解
注解功能的提供也有两者,一是Spring,二是Jdk (PS:类的注解只有springframework提供的)
@H_301_44@不必每次 写方法都得 标明:(方法.开始;方法.进行ing;方法.提交;方法.结束)
@H_301_44@百度云-ssh框架包-aop:http://pan.baidu.com/s/1pL4d3R1
@H_301_44@
@H_301_44@-------------------------------------------------------------
@H_301_44@1、已经注释的注解为:jdk注解;
@H_301_44@正在使用的注解为:spring的注解。
@H_301_44@3、使用注解就需要打包,这里已经删除了jdk注解带来的包。
@H_301_44@例如:
@Controller //控制层action的注解,与打包
@H_301_44@import org.springframework.stereotype.Controller;
@H_301_44@--------------------------------------------------------------
@H_301_44@一、项目分析
@H_301_44@
@H_301_44@
<span style="font-size:18px;color:#999999;">---------------新闻信息表 create database News; --建立数据库News; </span>
<span style="font-size:18px;color:#999999;">--建立表 news; create table news( id int primary key auto_increment,title varchar(50),content varchar(30),begintime datetime,username varchar(20) );</span>
<span style="font-size:18px;color:#999999;">--插入数据 insert into news(title,content,begintime,username) values ('IT市场分析','各门编程语言优势分析','2016-10-01','tom'),('如何不用加班','提高效率,减少上班时间','2016-10-02','tom2'),('如何实现加工资','提升自我价值与跳槽','2016-10-03','tom3'); use news1; select * form news; --查询表</span>
@H_301_44@
@H_301_44@news.action控制层:NewsAction
@Controller 和 @Scope("prototype") 2个注解取代xml处的代码:
<bena id ="" class="" scope="">
<prototype id="" red="" />
</bean>
package news.action; import java.util.List; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionSupport; import news.entity.News; import news.service.NewsService; //@Controller("myNewsAction") @SuppressWarnings("serial") @Controller //默认就是类的首字母小写newsAction @Scope("prototype") public class NewsAction extends ActionSupport { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } //获取从客户端传递过来的值,strtus自动的赋值 private Integer id; public Integer getId(){ return this.id; } public void setId(Integer id) { this.id = id; } @Autowired //@Qualifier("myNewsService") //@Resource(name="myNewsService") private NewsService ns; //定义1个list用于前端jsp显示 private List<News> allNewList; public List<News> getAllNewList() { return allNewList; } //显示首页所有数据 public String showAllNews(){ //调用service 中的showAllNews,获取所有的数据, //然后保存到 allNewList = ns.showAllNews(); return "success"; } //显示首页所有数据(查询使用的。PS:本例没用到) public String findNews(){ return ""; } public String deleteSingleNews(){ System.out.println("从客户端传递过来的ID:"+id); String returnValue = ns.deleteSingleNews(id); return returnValue; } }@H_301_44@news.dao sql访问层的NewsDao
@H_301_44@
package news.dao; import java.util.List; public interface NewsDao { public List showAllNews(); //显示首页所有数据(查询使用的。PS:本例没用到) public String findNews(); public String deleteSingleNews(Integer id); }
package news.dao; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.query.Query; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; import news.entity.News; //@Repository("myNewsDao") //jdk注解 @Repository <span style="white-space:pre"> </span> //sql访问层注解,规范 @Scope("prototype") //非单例 public class NewsDaoImpl implements NewsDao { //@Qualifier("mySessionFactory") //@Resource(name="mySessionFactory") @Autowired private SessionFactory sf; @Override public List showAllNews() { Session session = sf.getCurrentSession(); Query query = session.createQuery("from News"); allNewList = query.getResultList(); return allNewList; } @Override public String findNews() { return null; } @Override public String deleteSingleNews(Integer id) { Session session = sf.openSession(); Query query = session.createQuery("from News where id=:myid"); query.setParameter("myid",id); List<News> deleteList = query.getResultList(); //如果搜索出来是1条,就删除,如果是0条就不管了 if ( deleteList.size()==1 ) { News news = deleteList.get(0); System.out.println("删除对象:"+news.getTitle()+ " Id:"+news.getId()); session.getTransaction().begin(); session.delete(news); session.getTransaction().commit(); session.close(); //sessionFactory关闭策略 //1.坚持使用数据库连接池(例如C3P0) //2.sessionFactory就不关闭,而使用hibernate事务自动关闭功能 // 说明:sf.openSession(); 必须关闭 // sf.openSession(); 改为:sf.getCurrentSession(); //getCurrentSession创建的线程会在事务提交或者事务回滚后自动关闭 //sf.close(); } return "deleteOK"; } }
@H_301_44@news.entity 实体类层的 News 实体类
@H_301_44@
package news.entity; import java.util.Date; public class News { private Integer id; private String title; private String content; private Date begintime; private String username; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Date getBegintime() { return begintime; } public void setBegintime(Date begintime) { this.begintime = begintime; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }@H_301_44@news.entity包的 News.hbm.xml sql信息配置
<?xml version="1.0" encoding="UTF-8"?> <hibernate-mapping xmlns="http://www.hibernate.org/xsd/hibernate-mapping"> <class name="news.entity.News" table="news"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="title" type="string" length="50" column="title" not-null="true"></property> <property name="content" type="text" length="1000" column="content" not-null="true"></property> <property name="begintime" type="date" column="begintime" not-null="true"></property> <property name="username" type="string" length="20" column="username" not-null="true"></property> </class> </hibernate-mapping>
@H_301_44@news.service 业务逻辑处理层的 NewsService
package news.service; import java.util.List; public interface NewsService { public List showAllNews(); //显示首页所有数据(查询使用的。PS:本例没用到) public String findNews(); public String deleteSingleNews(Integer id); }@H_301_44@news.service 层的NewsServiceImpl业务逻辑处理层接口
package news.service; import java.util.List; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import news.dao.NewsDao; import news.entity.News; //@Service("myNewsService") //jdk注解 @Service<span style="white-space:pre"> </span> //业务逻辑处理层 注解,规范 @Scope("prototype") //非单例 public class NewsServiceImpl implements NewsService { //Autowired和Qualifier 属于spring的注解, //jdk自带注解resource可以替代Autowired /* * 用resource的好处: * 1. 代码与spring 解耦,不依赖于spring * 2. 代码中没有spring的存在,可以随时切换任意一套类似spring的框架 */ //@Qualifier("myNewsDao") //@Resource(name="myNewsDao") @Autowired private NewsDao nd; <pre name="code" class="java">@Override
@Transactional(readOnly=true) //事务处理=只读
public List showAllNews() { //可以增加一个业务逻辑,比如:把文章的内容进行截取为20字符 //通过DAO获取数据
List<News> allNewList = nd.showAllNews();
//在return 之间,可以进行各种业务逻辑操作 return allNewList; } @Override public String findNews() { return null; } <pre name="code" class="java">@Override
@Transactional //事务管理
public String deleteSingleNews(Integer id) { //需要做以下判断,例如有没有权限删除,又或者判断下面是否有级联子子记录 //当可以删除时,调用DAO给直接删除 String returnValue = "deleteFailed"; returnValue = nd.deleteSingleNews(id); return returnValue; } }
重点来了:applicationContext.xml
这里,之前<bean>的代码已经不要了,直接删除,写一个注解类的扫描器即可
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd"> <!-- 原理:自动注入processor解析器,用来解析注解 --> <!-- <context:annotation-config/> --> <!-- 自动扫描包,也会自动注入解释器,所以不需要 context:annotation-config --> <context:component-scan base-package="news"></context:component-scan> <!-- 引入外部属性文件 --> <context:property-placeholder location="classpath:jdbc.properties" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionfactorybean"> <!-- 注入连接池,包含了数据库用户名,密码等等信息 --> <property name="dataSource" ref="myDataSource" /> <!-- 配置Hibernate的其他的属性 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MysqL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.connection.autocommit">false</prop> <!-- 开机自动生成表 --> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> <property name="mappingResources"> <list> <value>news/entity/News.hbm.xml</value> </list> </property> </bean> <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.user}" /> <property name="password" value="${jdbc.password}" /> <!-- 每300秒检查所有连接池中的空闲连接 --> <property name="idleConnectionTestPeriod" value="300"></property> <!-- 最大空闲时间,900秒内未使用则连接被丢弃。若为0则永不丢弃 --> <property name="maxIdleTime" value="900"></property> <!-- 最大连接数 --> <property name="maxPoolSize" value="2"></property> </bean>
<!-- 加载一个事务管理驱动包 --> <span style="white-space:pre"> </span><bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <span style="white-space:pre"> </span><property name="sessionFactory" ref="sessionFactory"></property> <span style="white-space:pre"> </span></bean> <span style="white-space:pre"> </span> <!-- 注解驱动 --><span style="white-space:pre"> </span> <span style="white-space:pre"> </span><tx:annotation-driven transaction-manager="transactionManager"/> </beans>jdbc.properties sql表信息,这个是需要修改sql 的时候给其他不懂代码的人 修改配置的
jdbc.driver=com.MysqL.jdbc.Driver jdbc.url=jdbc:MysqL://localhost:3306/news jdbc.user=root jdbc.password= #oracle jdbc_oracle.driver=oracle.jdbc.driver.OracleDriver jdbc_oracle.url=jdbc:oracle:thin@127.0.0.1:1521:orcl jdbc_oracle.user=news jdbc_oracle.password=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> <constant name="struts.objectFactory" value="spring" /> <!-- 第1步:先定义一个包 --> <package name="mypck001" extends="struts-default"> <action name="NewsAction_*" class="newsAction" method="{1}"> <result name="success">/WEB-INF/jsp/index.jsp</result> <!-- 希望删除成功后,重新执行1次首页显示内容 --> <result name="deleteOK" type="redirectAction">NewsAction_showAllNews.action?message=deleteOk&id=${id}</result> </action> </package> </struts>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!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>Insert title here</title> <style> table{width:200px;border:1px solid black;text-align: center;} td{border:1px solid black;} </style> </head> <body> <center> 提示信息:<s:property value="message"/> 删除ID:<s:property value="id"/> <table> <s:iterator value="allNewList"> <tr> <td> <s:property value="id"/> </td> <td> <s:property value="title"/> </td> <td> <s:a value="NewsAction_deleteSingleNews?id=%{id}">删除</s:a> </td> </tr> <br> </s:iterator> </table> <hr> <h3>共有多少条记录:<s:property value="allNewList.size()"></s:property> </h3> </center> </body> </html>
@H_301_44@web.xml 配置信息
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>news1</display-name> <welcome-file-list> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <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> <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> </web-app>
default.jsp 重定向跳转主页面,隐藏主页面
NewsAction_showAllNews.action :调用NewsAction类 中的showAllNews的方法,
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% response.sendRedirect("NewsAction_showAllNews.action"); %>
lib目录下ssh框架配置jar包没有改变,还是之前的。
(参考网盘)
原文链接:https://www.f2er.com/xml/294743.html