1、ssh框架开发的应用层级结构

j2ee应用可以分为3层:

1、表示层


2、业务逻辑层


3、数据服务层

 

ssh将应用分层更加细化(ssh将业务逻辑层划分了4层):

1、action层(控制层mvc中的c层)


2、service层  (业务层mvc中的m层)


3、dao层(数据访问层)

4、entity层(数据实体层)

2、ssh中各个框架的作用

strust:

整个应用架构的骨架,负责应用中mvc模型的实现,向下层传递前端请求,向上层传递服务响应,主要作用于action层;

spring:

主要作用是依赖注入和控制反转以达到解耦的目的,用于对整个应用中的bean实例进行管理,作用于ssh各个层;

hibernate:

主要用于数据库操作,提供了便捷的数据库操作框架,主要作用于dao层;

3、ssh全注解框架搭建

 

1、创建web项目并勾选web.xml

2、导入ssh所需jar

 

        

ssh全注解框架整合_xml

ssh全注解框架整合_字段_02

 

可以去官网下载ssh所需jar包或者在我的资源中下载(解压后的lib文件夹中)

3、配置web.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID"version="2.5">
<display-name>demo1</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>

<filter>
<filter-name>action2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
<!-- 自动扫描action -->
<init-param>
<param-name>actionPackages</param-name>
<param-value>ssh.action</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>action2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring监听器配置开始 -->
<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>

4、配置spring的applicationContext.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
​​ http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd ​​
​​ http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd"​​>

<!-- <bean id="northMan"class="ssh.entity.NorthMan"></bean>
<beanid="southMan" class="ssh.entity.SouthMan"></bean>

-->
<!-- 自动扫描与装配bean -->
<context:component-scanbase-package="ssh.*"></context:component-scan>
<context:annotation-config/>
<!-- dbcp配置 -->
<beanid="dataSource"class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<propertyname="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<propertyname="url">
<value>jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false</value>
</property>
<propertyname="username">
<value>root</value>
</property>
<propertyname="password">
<value>root</value>
</property>
</bean>

<beanid="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<propertyname="dataSource">
<reflocal="dataSource"/>
</property>
<propertyname="hibernateProperties">
<props>
<!--配置Hibernate的方言 -->
<propkey="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<propkey="hibernate.hbm2ddl.auto">update</prop>

<!--格式化输出sql语句 -->
<propkey="hibernate.show_sql">true</prop>
<propkey="hibernate.format_sql">true</prop>
<propkey="hibernate.use_sql_comments">false</prop>
</props>
</property>

<!--自动扫描实体 -->
<propertyname="packagesToScan"value="ssh.entity"/>
</bean>

<!-- 用注解来实现事务管理 -->
<beanid="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<propertyname="sessionFactory"ref="sessionFactory"></property>
</bean>
<tx:annotation-driventransaction-manager="txManager"/>
</beans>

 

4、ssh中用到的注解标签(来源于网络)

strust:

命名空间注释(动作注释):


@ Namespace注释允许在Action类中,而不是基于零配置的约定动作的命名空间的定义。


@Namespace("/content")
public class Employee extends ActionSupport{
...
}
结果注释 - (动作译注):


@ Result注解允许在Action类中,而不是一个XML文件中定义的动作结果。


@Result(name="success", value="/success.jsp")
public class Employee extends ActionSupport{
...
}
结果注释 - (动作译注):


@ Results注解定义了一套动作的结果。


@Results({
@Result(name="success", value="/success.jsp"),
@Result(name="error", value="/error.jsp")
})
public class Employee extends ActionSupport{
...
}
注释后(拦截注释):


@After注解标志着一个需要调用后的主要操作方法和执行结果的操作方法。返回值将被忽略。


public class Employee extends ActionSupport{
@After
public void isValid() throws ValidationException {
// validate model object, throw exception if failed
}
public String execute() {
// perform secure action
return SUCCESS;
}
}
注释之前(拦截注释):


@ Before注释标记需要一个操作方法的主要操作方法之前被调用执行结果。返回值将被忽略。


public class Employee extends ActionSupport{
@Before
public void isAuthorized() throws AuthenticationException {
// authorize request, throw exception if failed
}
public String execute() {
// perform secure action
return SUCCESS;
}
}
BeforeResult注释 - (拦截注释):


@ BeforeResult注解标志着一个结果之前需要执行的操作方法。返回值将被忽略。


public class Employee extends ActionSupport{
@BeforeResult
public void isValid() throws ValidationException {
// validate model object, throw exception if failed
}

public String execute() {
// perform action
return SUCCESS;
}
}
ConversionErrorFieldValidator注释 - (验证译注):


此验证注解如果有任何转换错误进行了实地检查,并适用于他们,如果他们存在。


public class Employee extends ActionSupport{
@ConversionErrorFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getName() {
return name;
}
}
DateRangeFieldValidator注释 - (验证译注):


这验证注解检查日期字段的值在指定范围内。


public class Employee extends ActionSupport{
@DateRangeFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
min = "2005/01/01", max = "2005/12/31")
public String getDOB() {
return dob;
}
}
DoubleRangeFieldValidator注释 - (验证译注):


此验证注解检查双字段有一个值,该值在指定范围内。如果既不最小或最大,什么都不会做的。


public class Employee extends ActionSupport{

@DoubleRangeFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
minInclusive = "0.123", maxInclusive = "99.987")
public String getIncome() {
return income;
}
}
EmailValidator注释 - (验证译注):


这验证注解检查一个字段是一个有效的E-mail地址,如果它包含一个非空的字符串。


public class Employee extends ActionSupport{

@EmailValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getEmail() {
return email;
}
}
ExpressionValidator注释 - (验证译注):


这种非字段级验证验证所提供的正则表达式。


@ExpressionValidator(message = "Default message", key = "i18n.key",


shortCircuit = true, expression = "an OGNL expression" )


IntRangeFieldValidator注释 - (验证译注):


这验证注解检查一个数字字段的值在指定的范围内。如果既不最小或最大,什么都不会做的。


public class Employee extends ActionSupport{

@IntRangeFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
min = "0", max = "42")
public String getAge() {
return age;
}
}
RegexFieldValidator 注释 - (验证译注):


这个注解验证一个字符串字段,使用正则表达式。


@RegexFieldValidator( key = "regex.field", expression = "yourregexp")


RequiredFieldValidator 注释 - (验证译注):


这验证注解检查一个字段不为空。标注必须被应用在方法层面。


public class Employee extends ActionSupport{

@RequiredFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getAge() {
return age;
}
}
RequiredStringValidator注释 - (验证译注):


这验证注解检查一个字符串字段不为空(即非空,长度> 0)。


public class Employee extends ActionSupport{

@RequiredStringValidator(message = "Default message",
key = "i18n.key", shortCircuit = true, trim = true)
public String getName() {
return name;
}
}
StringLengthFieldValidator注释 - (验证译注):


这个验证检查字符串字段是合适的长度。假定该字段是一个字符串。如果设置既不是minLength 也不是最大长度,什么都不会做。


public class Employee extends ActionSupport{

@StringLengthFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
trim = true, minLength = "5", maxLength = "12")
public String getName() {
return name;
}
}
UrlValidator注释 - (验证译注):


这个验证检查一个字段是一个有效的URL。


public class Employee extends ActionSupport{

@UrlValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getURL() {
return url;
}
}
验证注释 - (验证译注):


如果想使用多个相同类型的注释,这些注释必须嵌套在@Validations() 注释。


public class Employee extends ActionSupport{

@Validations(
requiredFields =
{@RequiredFieldValidator(type = ValidatorType.SIMPLE,
fieldName = "customfield",
message = "You must enter a value for field.")},
requiredStrings =
{@RequiredStringValidator(type = ValidatorType.SIMPLE,
fieldName = "stringisrequired",
message = "You must enter a value for string.")}
)
public String getName() {
return name;
}
}
CustomValidator注释 - (验证译注):


这个注解可以用于自定义验证。使用ValidationParameter的注释,以提供额外的 params.


@CustomValidator(type ="customValidatorName", fieldName = "myField")
转换注释 - (类型转换注释):


这是一个标记注释类型转换类型级别。转换注释必须应用在类型级别。


@Conversion()
public class ConversionAction implements Action {
}
CreateIfNull注释 - (类型转换注释):


这个注解设置类型转换CreateIfNull。必须应用在域或方法级CreateIfNull注解。


@CreateIfNull( value = true )
private List<User> users;
元素注释 - (类型转换注释):


这个注解设置元素进行类型转换。必须应用在字段域或方法级元素的注解。


@Element( value = com.acme.User )
private List<User> userList;
关键注释 - (类型转换注释):


这个注解设置进行类型转换的关键。必须应用在域或方法级的关键注解。


@Key( value = java.lang.Long.class )
private Map<Long, User> userMap;
KeyProperty注释 - (类型转换注释):


这个注解设置类型转换KeyProperty。必须应用在域或方法级KeyProperty注解。


@KeyProperty( value = "userName" )
protected List<User> users = null;
TypeConversion注释 - (类型转换注释):


这个注解的注解是用于类和应用程序的转换规则。注解可以应用于TypeConversion在属性和方法的级别。


@TypeConversion(rule = ConversionRule.COLLECTION,
converter = "java.util.String")
public void setUsers( List users ) {
this.users = users;
}


 

spring :

使用 @Repository、@Service、@Controller 和 @Component 将类标识为 Bean
使用 @PostConstruct 和 @PreDestroy 指定生命周期回调方法
使用 @Required 进行 Bean 的依赖检查
使用 @Resource、@Autowired 和 @Qualifier 指定 Bean 的自动装配策略
使用 @Configuration 和 @Bean 进行 Bean 的声明
混合使用 XML 与注解进行 Bean 的配置
 

hibernate:

@Entity --注释声明该类为持久类。将一个Javabean类声明为一个实体的数据库表映射类,最好实现序列化.此时,默认情况下,所有的类属性都为映射到数据表的持久性字段.若在类中,添加另外属性,而非映射来数据库的,要用下面的Transient来注解.


@Table(name="promotion_info") --持久性映射的表(表名="promotion_info).@Table是类一级的注解,定义在@Entity下,为实体bean映射表,目录和schema的名字,默认为实体bean的类名,不带包名.


@Id--注释可以表明哪种属性是该类中的独特标识符(即相当于数据表的主键)。
@GeneratedValue --定义自动增长的主键的生成策略.
@Transient --将忽略这些字段和属性,不用持久化到数据库.适用于,在当前的持久类中,某些属性不是用于映射到数据表,而是用于其它的业务逻辑需要,这时,须将这些属性进行transient的注解.否则系统会因映射不到数据表相应字段而出错.
@Temporal(TemporalType.TIMESTAMP)--声明时间格式
@Enumerated --声明枚举
@Version --声明添加对乐观锁定的支持
@OneToOne --可以建立实体bean之间的一对一的关联
@OneToMany --可以建立实体bean之间的一对多的关联
@ManyToOne --可以建立实体bean之间的多对一的关联
@ManyToMany --可以建立实体bean之间的多对多的关联
@Formula --一个SQL表达式,这种属性是只读的,不在数据库生成属性(可以使用sum、average、max等)
@OrderBy --Many端某个字段排序(List)
1.2
Hibernate 能够出色地自动生成主键。Hibernate/EBJ 3 注释也可以为主键的自动生成提供丰富的支持,允许实现各种策略。
其生成规则由@GeneratedValue设定的.这里的@id和@GeneratedValue都是JPA的标准用法, JPA提供四种标准用法,由@GeneratedValue的源代码可以明显看出.
JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO.
TABLE:使用一个特定的数据库表格来保存主键。
SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
IDENTITY:主键由数据库自动生成(主要是自动增长型)
AUTO:主键由程序控制。


在指定主键时,如果不指定主键生成策略,默认为AUTO。
@Id
相当于
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
identity:
使用SQL Server 和 MySQL 的自增字段,这个方法不能放到 Oracle 中,Oracle 不支持自增字段,要设定sequence(MySQL 和 SQL Server 中很常用)。
Oracle就要采用sequence了.
同时,也可采用uuid,native等其它策略.(相关用法,上网查询)
[2]
第一个持久性类
@Entity
@Table(name="T_MODEL_PLANE")
public class ModelPlane implements Serializable {
@Id
@Column(name="PLANE_ID")
@GeneratedValue(strategy=GenerationType.AUTO) //注解于属性中
/*
对于oracle想使用各自的Sequence,设置如下:
@GeneratedValue(strategy = GenerationType.AUTO,generator="PROMOTION_SEQ")
@SequenceGenerator(name="PROMOTION_SEQ",sequenceName="PROMOTION_SEQ")
另外:
对于自动增长后,在数据表中的相应字段,要设置字段为auto_increment.
*/
private Long id;


private String name;//注解写于getter方法之上.请见下.


//DATE - java.sql.Date
//TIME - java.sql.Time
//TIMESTAMP - java.sql.Timestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name="start_time")
private Date startTime;


//显示0 隐藏1
public static enum DisplayType {显示,隐藏}
@Enumerated(value = EnumType.ORDINAL)//ORDINAL序数
private DisplayType displayType = DisplayType.显示;


//1.sql语句中的字段和表名都应该和数据库相应,而不是类中的字段,
//若带有参数如la.id= id,这个=id才是类中属性
//2.操作字段一定要用别名
@Formula(select COUNT(la.id) from largess la)
private int count;


//注解于方法中
@Column(name="PLANE_ID", length=80, nullable=true) //较详细定义
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
其它的setter,getter省略......
}


该内容将映射到下表中:
CREATE TABLE T_MODEL_PLANE
(
PLANE_ID long,
PLANE_NAME varchar
其它字段省略...
)


默认情况下,Hibernate 会将持久类以匹配的名称映射到表和字段中。例如,下例中,若不用注解,则会映射到如下一表中:
CREATE TABLE MODELPLANE
(
ID long,
NAME varchar


其它字段省略...
)


[3]
一对多注解:
1.
在一对多注解中,会用到:
"一"方:
@OneToMany --> mappedBy:"多"方的关联属性(被控方)
"多"方:
@ManyToOne --> @JoinColumn,"多"方定义的外键字段.
如数据表定义外键如下:
FOREIGN KEY (classid) REFERENCES classes(id)
则:
@JoinColumn(name="classid")
2.
在双向关联中,有且仅有一端作为主体(owner)端存在:主体端负责维护联接列(即更新),对于不需要维护这种关系的从表则通过mappedNy属性进行声明。mappedBy的值指向另一主体的关联属性。例子中,mappedBy的值为classes。
附加说明:
mappedBy相当于过去的inverse="true".
inverse=false的side(side其实是指inverse=false所位于的class元素)端有责任维护关系,而inverse=true端无须维护这些关系。
3.
cascade与fetch使用说明:
Cascade
CascadeType.PERSIST (级联新建)
CascadeType.REMOVE (级联删除)
CascadeType.REFRESH (级联刷新)
CascadeType.MERGE (级联更新)中选择一个或多个。
CascadeType.ALL
fetch属性:
关联关系获取方式,即是否采用延时加载。
LAZY(默认值)采用延时加载,查询数据时,不一起查询关联对象的数据。而是当访问关联对象时(如:getStudnets()时)才触发相应的查询操作,获取关联对象数据。
EAGER:是在查询数据时,也直接一起获取关联对象的数据。
package oneToMany;
import java.util.Set;
import javax.persistence.*;
/*
注意导入时,是导入:import javax.persistence.*;
非导入org.hibernate的相关类:import org.hibernate.annotations.Entity;
*/
@Entity
@Table(name="classes")
public class Classes implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;


@OneToMany(cascade=CascadeType.ALL,mappedBy="classes")
private Set<Student> students;
//getter,setter省略
}




package oneToMany;
import javax.persistence.*;
@Entity
@Table(name="student")
public class Student implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int sid;


private String sname;


//若有多个cascade,可以是:{CascadeType.PERSIST,CascadeType.MERGE}
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="classid") //student类中对应外键的属性:classid
private Classes classes;
//getter,setter省略
}




public class TestOneToMany {
/*
CREATE TABLE student ( --要定义外键!!!!!!!
`sid` double NOT NULL auto_increment,
`classid` double NULL,
`sname` varchar(255) NOT NULL,
PRIMARY KEY (sid),
INDEX par_ind (classid),
FOREIGN KEY (classid) REFERENCES classes(id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
*/
public static void main(String[] args) throws SQLException
{
try
{
SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
/*
因为mappedBy是定义在classes中,即classes类不负责维护级联关系.即维护者是student.所以,
1.要将clsses的数据,赋给student,即用student的setClasses()方法去捆定class数据;
2.在进行数据插入/更新session.save()/session.update()时,最后操作的是student.
*/
Classes classes=new Classes();
classes.setName("access");


Student st1=new Student();
st1.setSname("jason");
st1.setClasses(classes);
session.save(st1);


Student st2=new Student();
st2.setSname("hwj");
st2.setClasses(classes);
session.save(st2);
tx.commit();
/*
输出如下:
Hibernate: insert into classes (name) values (?)
Hibernate: insert into student (classid, sname) values (?, ?)
Hibernate: insert into student (classid, sname) values (?, ?)
*/


/*
因为一端维护关系另一端不维护关系的原因,我们必须注意避免在应用中用不维护关系的类(class)建立关系,因为这样建立的关系是不会在数据库中存储的。
如上的代码倒过来,则插入时,student的外键值为空.如下:
*/
// Student st1=new Student();
// st1.setSname("jason");
// session.save(st1);
//
// Student st2=new Student();
// st2.setSname("hwj");
// session.save(st2);
//
// Set<Student> students=new HashSet<Student>();
// students.add(st1);
// students.add(st2);
//
// Classes classes=new Classes();
// classes.setName("access");
// classes.setStudents(students);
// session.save(classes);
/*
输出如下:
Hibernate: insert into student (classid, sname) values (?, ?)
Hibernate: insert into student (classid, sname) values (?, ?)
Hibernate: insert into classes (name) values (?)
*/
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
}




[4]
多对多注解:
在多对多注解中,双方都采用@ManyToMany.
其中被控方,像一对多注解中设置一样,也要设置mappedBy.
其中主控方,不像一对多注解那样,采用@joinColumn,而是采用@joinTable.如下:
@JoinTable(name="j_student_course" ,joinColumns={@JoinColumn(name="sid")},inverseJoinColumns={@JoinColumn(name="cid")})
其中,
如上所说,mappedBy,相当于inverse="true".所以,在@joinTable中的inverseJoinColumns中定义的字段为mappedBy所在类的主键.
joinColumns定义的字段,就是当前类的主键.
@Entity
@Table(name="jcourse")
public class Jcourse {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int cid;
private String cname;


@ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.LAZY ,mappedBy="courses")
private Set<Jstudent> students;
//setter,getter省略....
}




@Entity
@Table(name="jstudent")
public class Jstudent {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int sid;


private String sname;


@ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE},fetch=FetchType.EAGER)
//inverseJoinColumns中对应的id为以下属性course的对应id.
@JoinTable(name="j_student_course" ,joinColumns={@JoinColumn(name="sid")},inverseJoinColumns={@JoinColumn(name="cid")})
private Set<Jcourse> courses;
//setter,getter省略....
}




public class Test {
public static void main(String[] args) {
try
{
SessionFactory sf = new AnnotationConfiguration().configure().buildSessionFactory();
Session session=sf.openSession();
Transaction tx=session.beginTransaction();


Jcourse course=new Jcourse();
course.setCname("jason-english");
session.save(course); //先各自保存.


Jcourse course2=new Jcourse();
course2.setCname("herry-english");
session.save(course2);


Set<Jcourse> courses=new HashSet<Jcourse>();
courses.add(course);
courses.add(course2);


Jstudent student=new Jstudent();
student.setSname("jason");
student.setCourses(courses);


session.save(student);// 要用非mapby定义的类(studet)来作为主者(会控制级联关系),一对多,多对一也一样道理.
//可以尝试反过来.
tx.commit();
}
catch(HibernateException e)
{
e.printStackTrace();
}
} }

 

源码地址:

 

​https://github.com/duoluo9/ssh-conformity​