【SSH 框架项目的搭建--简化版】使用注解代替xml中的<bean>,减少代码量

之前的《图书信息管理系统》项目中(http://blog.csdn.net/ssh159/article/details/52439676),

Spring的配置太繁琐。考虑开发大项目上,假设项目的action层会有成百上千 个Class类,不简化代码的

情况下就要在Spring的配置中装配上千个actionClass的<bean>,applicationContext.xml的代码太多了。


改进代码:

1、使用注解 代替applicationContext.xml中的 <bean> 标签,添加 注解扫描器,解析器。

简化 xml处的配置信息。

2、使用Aop,只保留事务处理的代码(只保留核心关注点横切关注点),删掉多余的动作;

(这是面向切面的知识,不懂可以看看我之前写的

【java初学者】理解,从面向过程 到 面向对象,面向接口,面向切面例子。)

简化 各层的代码。


(之前的博客:【JAVA】理解MVC模式,IOC,AOP,orm框架,SOA,ERP管理系统

AOP:将应用程序中的商业逻辑及对其提供支持的 应用服务 进行分离。
商业逻辑:

核心关注点(主要是带入对象和对象的特殊事务),

横切关注点(经常发生在核心关注点的各处,各处都基本相似,用以:权限认证,日志,事务处理)。
通用服务:做记录,日记。



之前的写法:

因为不想new 对象,所以在application中,

1、一个类和2个接口(IndexAction,IndexServiceImpl,IndexDaoImpl)都要标明非单例;

2、用<bean> <prototype>标签 取代那些私有属性(is,id,sessionFactory)new对象;

3、私有属性(is,sessionFactory)还要设置属性和方法;


IndexAction 控制层的代码:

private IndexService is = null;  
    public void setIs(IndexService is) {  
        this.is = is; 

IndexServiceImpl 业务逻辑处理层接口 的代码:

 private IndexDao id;  
//用于注入使用 
    public void setId(IndexDao id) {  
        System.out.println("有人给我注入了一个dao实例:"+id);  
        this.id = id;  
    }  

IndexDaoImpl 数据库访问层接口 的代码:

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>  


感觉代码实在是太多了,所以 现在用注解的方式,减少代码!


现在解决方案:

1、 在项目中加入注解:

让Spring自动的为Class类定义的属性装配bean以及让Spring自动的扫描程序包中的类,隐式的在配置文件中

添加Class类的bean。

  注解分为两种,一是类的注解,二是类中属性的注解

  注解功能的提供也有两者,一是Spring,二是Jdk PS:类的注解只有springframework提供的

2、使用事务处理,删除多余的信息,

不必每次 写方法都得 标明:(方法.开始;方法.进行ing;方法.提交;方法.结束)

3、增加四个aop 的jar包:解耦

百度云-ssh框架包-aop:http://pan.baidu.com/s/1pL4d3R1


-------------------------------------------------------------

温馨提示:

1、已经注释的注解为:jdk注解;

正在使用的注解为:spring的注解。

2、2种注解都可以,只是规范代码。

3、使用注解就需要打包,这里已经删除了jdk注解带来的包。

例如:

@Controller //控制层action的注解,与打包

import org.springframework.stereotype.Controller;

--------------------------------------------------------------

一、项目分析


二、mysql建表

<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>



三、java代码:

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;
}

}
news.dao sql访问层的NewsDao

package news.dao;

import java.util.List;

public interface NewsDao {
	public List showAllNews();
//显示首页所有数据(查询使用的。PS:本例没用到)
	public String findNews();
	public String deleteSingleNews(Integer id);
}


news.dao sql访问层的NewsDaoImpl接口
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";
}


}

news.entity 实体类层的 News 实体类

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;
	}
	

}
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>

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);
}
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 的时候给其他不懂代码的人 修改配置的

这里支持mysql 和 oracle ,密码为空

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>


jsp页面:index.jsp 主页

<%@ 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>

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包没有改变,还是之前的。

(参考网盘)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇