Model(javabean技术)-View(jsp技术)-Control(servlet技术)
entity层-dao层(Hibernate/MyBatis)-service层(Spring)-web层(Struts2/SpringMVC)
SSH(Hibernate+Spring+Struts2)-SSM(MyBatis+Spring+SpringMVC)
Hibernate
EJB:EJB3.0
实体bean:Entity Bean;实现O/R映射
会话bean:Session Bean;实现业务逻辑
消息驱动bean:MessageDriven Bean;只能接收客户端发送的JMS消息然后处理
点对点: 中间件(用户a->服务器->用户b)
pub/sub:发布/订阅模型
ORM(对象-关系映射):Object Relational Mapping,
对象三种状态:自由状态/瞬时状态 持久状态 脱管状态/游离状态
持久化:将程序中数据在瞬时状态和持久状态键转换的机制
持久化层:DAO层(数据访问层)
- jdbc连接数据库的参数
- 方言
- 类---表
- 属性---字段
Hibernate框架:持久层(Dao层)框架
Hibernat配置流程:
- 添加jar包(hibernate3.jar、/required/、ojdbc6.jar、slf4j.jar、log4j.jar、slf4j-log4j.jar)
hibernate3.jar + required 目录中所有 + jpa + 数据库驱动包
antlr-2.7.6.jar
commons-collections-3.1.jar
dom4j-1.6.1.jar
hibernate-jpa-2.0-api-1.0.0.Final.jar
hibernate3.jar
javassist-3.12.0.GA.jar
jta-1.1.jar
mysql-connector-java-5.1.12-bin.jar
slf4j-api-1.6.1.jar
- 添加Hibernate配置文件(hibernate.cfg.xml)
<hibernate-configuration>
<session-factory>
<!-- 数据库连接 -->
<property name="myeclipse.connection.profile">t38_oracle</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:orcl
</property>
<property name="connection.username">t38</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">
oracle.jdbc.OracleDriver
</property>
<!-- 辅助参数 -->
<!-- 方言 -->
<property name="dialect">
org.hibernate.dialect.Oracle9Dialect
</property>
<!-- 显示sql语句 -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- 引入映射文件 -->
<mapping resource="com/hfxt/entity/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
- 添加实体类和实体类的映射文件(User--User.hbm.xml)
//实体类User(javaBean):持久化类
public class User implements Serializable {
//自动生成的串号
private static final long serialVersionUID = 7373379251590476940L;
private Integer id;
private String username;
private String password;
private Integer status;
private Date createtime;
private Integer roleId;
}
//实体类映射文件User.hbm.xml:
<hibernate-mapping package="com.hfxt.entity">
<class name="User" table="TB_USER">
<!-- 唯一标识:属性-主键 -->
<id name="id" column="ID" type="java.lang.Integer">
<!-- 主键生成策略 -->
<generator class="sequence">
<param name="sequence">SEQ_USER</param>
</generator>
</id>
<property name="username" column="USERNAME" type="java.lang.String" ></property>
<property name="password" column="PASSWORD" type="java.lang.String" ></property>
<property name="status" column="STATUS" type="java.lang.Integer"></property>
<!-- 设置修改时不更新 -->
<property name="createtime" column="CREATETIME" type="java.util.Date" update="false"></property>
<property name="roleId" column="ROLE_ID" type="java.lang.Integer"></property>
</class>
</hibernate-mapping>
Test类:
public class Test {
public static void main(String[] args) {
User item = new User();//创建增加对象
item.setUsername("bn");
item.setPassword("456");
item.setStatus(1);
item.setCreatetime(new Date());
item.setRoleId(1);
//1.加载配置文件
Configuration cfg = new Configuration().configure();
//2.得到SessionFactory 重量级的 线程安全的
SessionFactory sf = cfg.buildSessionFactory();
//3.得到Session 轻量级的 非线程安全的
Session session = sf.openSession();
/* ThreadLocal:本地线程的私有空间
* 配置HibernateSessionFactory类
Session session = HibernateSessionFactory.getSession();*/
Transaction tx = null;
try {
//4.开启事务(增、删、改)
tx = session.beginTransaction();
//5.持久化操作
//增加
session.save(item);
//item.setUsername("xxx");//持久化写入
/*//先得到,再修改
User item = (User) session.get(User.class, 23);//先得到
item.setUsername("**");
item.setPassword("789");
session.update(item);
//先得到,再删除
User item = (User) session.get(User.class, 23);//先得到
session.delete(item);*/
//6.提交事务
tx.commit();
} catch (Exception e) {
e.printStackTrace();
if(tx != null) tx.rollback();
} finally{
//7.关闭session
session.close();
}
}
}
为工程添加Hibernate支持:MyEclipse>Add Hibernate Capabilities
>com.hfxt.dao.impl>HibernateSessionFactory类
static {
try {
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();//threadLocal:本地线程的私有空间 线程安全
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory!=null) ? sessionFactory.openSession(): null;
threadLocal.set(session);
}
return session;
}
Hiberante API:
|-- Session 一个与数据库连接的会话信息
Sesison里面维护了一个连接对象,且对常用操作进行封装!
更新:
session.save(obj); 保存一个对象
session.update(obj) 更新一个对象, 注意修改对象的主键一定要在数据库存在!
session.saveOrUpdate(obj) 保存或更新
如果有设置主键且主键存在执行更新!
没有设置主键执行保存!
session.delete(obj) 删除一个对象; 注意修改对象的主键一定要在数据库存在!
主键查询:
Session.get(clazz,id); 根据主键查询
Session.load(clazz,id); 根据主键查询
HQL查询(Hibernate Query language):面向对象的查询语言,查询对象、对象的属性
<!-- 关键字不区分大小写,类名和属性名区分大小写 -->
[select ...] from Entity [where ...] [group by ] [having ] [order by ]
update Entity set...[where ]
delete from Entity [where ]
HQL与SQL区别:
Hql 查询的是对象、对象的属性,区分大小写!
Hql查询的对象一定要有映射!
SQL 查询的是表、字段,不区分大小写!
HQL的使用:
//1 创建Session
Session session = HibernateSessionFactory.getSession();
//2 编写hql语句
String hql = "from User";
//String hql = "from User where username=? and password=?";
//String hql = "from User where username=:uname and
password=:upass";//命名参数查询
//3 创建Query对象
Query query = session.createQuery(hql);
//query.setString(0,"张三");
//query.setString(1, "123");
//query.setString("uname","张三");
//query.setString("upass", "123");
// 分页
int currentPage = 1;
int pageSize = 3;
query.setFirstResult((currentPage-1)*pageSize);
query.setMaxResults(pageSize);
//4 执行查询,得到结果
List<User> list = query.list();//根据结果集变换类型
for(User user : list){
System.out.println(user.getUsername());
}
Hibernate执行流程:
hibernate.cfg.xml配置详解:
hibernate-distribution-3.6.0.Final\project\etc\hibernate.properties
#hibernate.dialect org.hibernate.dialect.MySQLDialect
#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
#hibernate.connection.driver_class com.mysql.jdbc.Driver
#hibernate.connection.url jdbc:mysql:///test
#hibernate.connection.username gavin
#hibernate.connection.password
自动建表:
#hibernate.hbm2ddl.auto create-drop 每次在创建sessionFactory的时候创建表;执行sf.close()删除表
#hibernate.hbm2ddl.auto create 每次都先删除表,再创建新的表
#hibernate.hbm2ddl.auto update 如果表不存在则创建,存在就不创建!
#hibernate.hbm2ddl.auto validate 检查映射配置与数据库结构是否一致,不一致就报错
映射配置:映射文件(*.hbm.xml),描述“对象”与“表”的映射关系
<!--
通过XML映射,把对象映射到数据库的表中
package 表示包名; 可选,如果没有写,后面的类必须指定类的全名!
auto-import="true" 默认为true,即在写hql的时候,会自动引入包名;
如为false,hql中对象要写上包名称
Query q = session.createQuery("from Users");
-->
<hibernate-mapping package="cn.itcast.b_api" auto-import="true">
<!--
class 表示映射的一个javabean对象(可以有多个class节点,但一般一个映射文件对应一个class)
name 表示映射的类的名称;
table (可选)类的名称,对应的表名, 如果不写默认与类名称一样
-->
<class name="Users" table="t_users">
<!--
id 表示映射的是主键
注意: 在hibernate的映射文件中,必须要有主键映射!
generator 表示的是主键生成策略 (Api : Various additional generators)
class
identity 主键自增长, mysql/sqlservlet等数据库使用的自增长的方式
sequence 以序列的方式实现自增长;
native 表示主键自增长: 根据底层数据库的能力选择 identity、sequence等其中一个。
assigned 手动指定主键的值
uuid uuid的值作为主键,确保一定唯一
-->
<id name="userId" column="id">
<generator class="native"></generator>
</id>
<!--
property 表示普通字段的映射
name 属性的名称
column 可选,如果没有指定,与属性名称一致
length 表示字符长度,只对字符类型有效
type 数据库中字段的类型 (如果没有指定,会匹配属性的类型)
hibernate中指定的类型: 小写开头
java中类型: 写类的全名
unique 设置为true,表示给当前列添加唯一约束
(主键约束 = 唯一约束 + 非空)
-->
<property name="userName" type="java.lang.String" column="username" length="50" unique="true"></property>
<property name="age" column="age" type="int"></property>
<!-- 注意:如果列名称对应的是数据库的关键字,需要处理 -->
<property name="desc" column="`desc`" length="200"></property>
</class>
</hibernate-mapping>
hibernate对象状态:临时状态(new)-持久化状态(session)-游离状态(session关闭)
session.save(对象);
- 临时状态
1 . 直接new出来的对象
2. 不处于session的管理(即没有与任何一个session关联)
3. 对象在数据库中没有对应的记录!
Employee e = new Employee();
e.setId(2); 只要主键在数据库中存在,就说这个对象在数据库中有对应记录!
在数据库中叫主键!
OID, object identified 对象的唯一标识 (对应数据库中的主键)
(二) 持久化状态
1. 处于session的管理范围
当执行session的方法如:save/update/saveOrUpdate/get/load
对象就会自动转变为持久化状态!
2. 在数据库中有对应的记录
3. 处于持久化状态的对象,当对对象属性进行更改的时候,提交事务更改会反映到数据库中!
(三) 游离状态
1. 对象不处于session的管理范围;通常指session关闭后对象的状态
2. 对象在数据库中有对应的记录
UML:Unified Modeling Language,统一建模语言
工具:powerdesigner、visio、national rose
类图:关联、依赖、泛化、组合、聚合
关联关系:A关联B
public class A{
private B b;
private List<B> list;
}
依赖关系:A依赖B
public class A{
public void add(B b){
}
}
对象关联关系:种类(一对多关联/一对一关联/多对多关联)-方向(单向/双向关联)
主键表-外键表 主表-子表 主键-外键
配置多对一关联:student--grade
- 外键改为对象:Student类中(private Grade grade;)
- 实体类映射文件配置many-to-one:Student.hbm.xml(
<!-- 多对一:grade类-student外键 -->
<many-to-one name="grade" column="GID" class="Grade"></many-to-one>
配置一对多关联:grade--student
- 添加多的容器:
Grade类(private Set<Student> students = new HashSet<Student>();)
- 实体类映射文件配置one-to-many: Grand.hbm.xml
<!-- set集合 -->
<set name="students">
<key column="GID"></key>
<one-to-many class="Student" />
</set>
配置多对多关联:student--sc--course(相当于两个一对多)
- 添加多的容器:
Student类:private Set<Course> courses = new HashSet<Course>();
Course类:private Set<Student> students = new HashSet<Student>();
- 映射文件配置:
Student.hbm.xml:
<set name="courses" table="SC">
<key column="SID"></key>
<many-to-many column="CID" class="Course"></many-to-many>
</set>
Course.hbm.xml:
<set name="students" table="SC">
<key column="CID"></key>
<many-to-many column="SID" class="Student"></many-to-many>
</set>
ManyToManyTest类:
Session session = HibernateSessionFactory.getSession();
Student s = (Student) session.get(Student.class, 1);
Set<Course> courses = s.getCourses();
for(Course course : courses){
System.out.println(course.getCname());
}
session.close();
cascade属性:级联
all、save-update(保存更新进行级联操作)、delete、none
inverse属性:控制反转,指定关联关系中的方向
inverse=”false”:由主动方维护关联关系
inverse=”true”: 由对方维护关联关系
Hibernate默认:默认false,只能改set中为true;一对多关联中,将一方的inverse改为true,有助于性能的改善
<!-- 级联删除 -->
<set name="students" inverse="true" cascade="delete/all">
<key column="GID"></key>
<one-to-many class="Student" />
</set>
级联删除:先维护关系,再删除
<set name="students" inverse="true" cascade="delete" />
<set name="students" cascade="delete">+Student表的GID(Nullable:true)
级联增加:先增加,再维护关系
级联修改:先维护关系,再修改,再维护关系
//先增加年级,再级联增加学生(先增加主表再增加子表)
Grade grade = new Grade();
grade.setGid(1);
grade.setGname("T35");
Student s1 = new Student();
s1.setSid(1);
s1.setSname("张三");
s1.setSex("男");
s1.setGrade(grade);//设置年级(手工设置关系) 自动维护关系:inverse="true"并且student表GID(Nullable:true)
Student s2 = new Student();
s2.setSid(2);
s2.setSname("李四");
s2.setSex("女");
s2.setGrade(grade);
Student s3 = new Student();
s3.setSid(1);
s3.setSname("王五");
s3.setSex("男");
s3.setGrade(grade);
//级联操作
grade.getStudents().add(s1);
grade.getStudents().add(s2);
grade.getStudents().add(s3);
Session session = HibernateSessionFactory.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.save(grade);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
if(tx != null){
tx.rollback();
}
} finally{
session.close();
}
}
Hibernate加载方式:延迟加载(默认)、立即加载
//默认延迟加载:
Session session = HibernateSessionFactory.getSession();
Student s = (Student) session.get(Student.class, 1);
System.out.println("--------------");
System.out.println(s.getGrade().getGname()+":"+s.getSname());
session.close();
//立即加载:fetch=”select/join”
<!-- 立即加载 fetch:sql查询语句内联 -->
<many-to-one name="grade" column="GID" class="Grade" fetch="join" />
Hibernate缓存:
缓存分类:事务级别缓存、应用程序级别缓存、分布式缓存
缓存作用范围:事务范围 进程范围 集群范围
一级缓存:Session缓存,依赖于Session生命周期
清理缓存的方法:evict(Obeject obj)//清空对象、clear()//全部清空
二级缓存:SessionFactory外置缓存,依赖于SessionFactory的生命周期
Hibernate默认提供的是HashtableCache的二级缓存实现,它仅仅用于开发测试
通常配置一个第三方的缓存插件(EHCache、OsCache、SwarmCache、JBossCache)
二级缓存默认开启,配置文件中添加cache.user_second_level_cache,值为false可以关闭
配置二级缓存:
- 添加ehcache.jar (依赖包commons-logging-1.1.1.jar)
- 在src下,添加ehcache.xml文件,文件模板在Hibernate源代码文件的etc文件夹下
<!-- 默认缓存策略 -->
<defaultCache
maxElementsInMemory="10000"--最大内存容量
eternal="false"--永不过期false
timeToIdleSeconds="120"--最大空闲时间
timeToLiveSeconds="120"--最大存活时间
overflowToDisk="true"--内存溢出存磁盘true
/>
<!-- 自定义缓存策略 -->
<cache name="com.hfxt.entity.User"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
- 在配置文件添加cache.provider_class,值为:org.hibernate.cache.EhCacheProvider
默认cache.use_second_level_cache:true
- 在要使用缓存的类的映射文件中,在class节点下配置:<cache usage=”read-write” />
Hibernate查询:
get/load方法:
get方法:
1 在使用get方法查询的时候,它就会发送SQL语句,查询数据库,而不是在调用它的某个属性的时候
2 在查询数据库,找不到的情况下,返回null;
load方法:
1 在调用它的某个属性的时候才会去发送SQL语句,查询数据库
2 找不到的情况下,就报异常
Session session = HibernateSessionFactory.getSession();
User item1 = (User) session.get(User.class, 21);//get立即发送sql
System.out.println("-----------------------------");
System.out.println(item1.getUsername());
System.out.println("++++++++++++++++++++++++++++++");
session.close();//关闭一级缓存
session = HibernateSessionFactory.getSession();
//session.clear();//清空session缓存
//session.evict(item1);//清空一个对象缓存
User item2 = (User) session.load(User.class,21);//load需要时发送sql 创建虚拟对象item2
System.out.println("------------------------------");
System.out.println(item2.getUsername());
session.close();
查询缓存:查询结果缓存,查询对象集合依赖于一级二级缓存;主要用于通过hql或qbc查询的缓存,主要对list起作用;
默认关闭的,通过在配置文件中配置cache.use_query_cache,值为true来开启,然后必须在代码中设置query.setCacheable(true)才能使用
list()/iterate()方法:
iterate:查询对象的时候,先查询所有id,在使用的时候,根据id去一级缓存,二级缓存中去查询实体对象,如果查不到,根据id,逐个发送sql语句去数据库中查(N+1次问题)
list:查询缓存中会保存sql,结果集,不依赖于二级缓存,只存不取
第一次使用查询缓存和list查询的时候,得到 :
1.查询结果
2.如果是对象,它把结果放入一级缓存和二级缓存
3.如果是对象数组,把sql语句、id、类型放入查询缓存中
再一次使用list查询同样的hql的时候,会取得查询缓存里面的id去一二级缓存中查询,如果查不到,根据id查询数据库(N次问题)
Session session = HibernateSessionFactory.getSession();
String hql = "from User";
Query query1 = session.createQuery(hql);
List<User> list = query1.list();//list()立即加载
for(User u : list){
System.out.println(u.getUsername());
}
System.out.println("++++++++++++++++++++++++++");
session.close();
session = HibernateSessionFactory.getSession();
Query query2 = session.createQuery(hql);
Iterator<User> it = query2.iterate();//iterate()延迟加载
while(it.hasNext()){
User u = it.next();
System.out.println(u.getUsername());
}
session.close();
Hibernate注解:
配置实体类注解:
@Entity:声明实体bean(持久化POJO类)
@Id:实体bean标识属性(数据表的主键)
@Generated:标识符的生成策略
@Table:实体bean映射指定表
@UniqueConstraint:表的唯一约束
@Column:属性映射到列
配置对象关联关系注解:@OneToMany @ManyToOne @ManyToMany
配置命名查询注解:@NamedQuery
Struts2
Struts2:基于MVC的Web应用框架,对servlet技术的封装
Struts2=WebWork技术+Struts1的知名度和市场
Action(业务控制器):用户(*.action)>ActionServlet(总控制器)>SubAction(execute方法)
Struts2使用步骤:
- 导入struts2支持的jar包
commons-beautils [beanutils工具包]
commons-filupload.ajr、commons-io.jar [文件上传]
commons-lang [struts2对java.lang.*类的支持]
freemarker.jar [视图显示技术]
javassit [struts2对字节码运算的支持]
ognl.jar [struts2对ognl表达式的支持]
struts2-core.jar [ struts2的核心包]
xwork-core.jar [webwork框架的支持,struts2的前身就是webwork(对webwork的封装)]
- web.xml中配置启动的全局过滤器Filter(类似ActionServlet)
<!-- 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>
- 创建业务Action类,编写业务方法,默认execute方法:继承ActionSupport(实现Action接口)
//HelloAction
public class HelloAction extends ActionSupport{
private String message;//属性方式传参
//处理请求的方法: 默认execute方法
public String execute() throws Exception{
message = "Hello,struts2 ";
return SUCCESS;//字符串常量:SUCCESS="success"
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- src/struts.xml,配置Action对象:
<struts>
<!-- 动态方法调用 /hello!reg 禁用>default properties-->
<constant name="struts.enable.DynamicMethodInvocation"
value="false" />
<package name="default" extends="struts-default" namespace="">
<!-- 配置Action: 浏览器访问localhost:8080/struts2demo/hello -->
<!-- hello(action别名)>处理请求的类>处理请求的方法(默认execute) -->
<action name="hello" class="com.hfxt.web.action.HelloAction" method="execute">
<!-- 结果视图:type默认是dispatcher(转发),redirect(重定向) -->
<result name="success" type="dispatcher">/index.jsp</result>
<result name="error" type=" redirect">/error.jsp</result>
</action>
</package>
</struts>
- 浏览器访问业务方法:localhost:8080/struts2demo/hello,转发到index.jsp:
<body>
${message }
</body>
Struts2执行过程:
项目启动:
1)创建核心过滤器StrutsPrepareAndExecuteFilter对象
2)执行核心过滤器的init方法,读取了依次以下的配置:
struts-default.xml [struts2框架的默认配置文件(不需要自定修改)]
struts-plugin.xml [struts2的插件配置文件]
struts.xml [业务配置文件(包含配置的Action)]
访问资源:
3)在内存中查询对应的Action配置,得到class内容,创建Action对象
4)读取Action配置的method内容,执行Action对象对应的方法
struts-default.xml(对象bean>默认包(跳转类型|拦截器))-struts.xml(包package>Action>result)
struts-default.xml文件详解:
1)声明struts2框架运行过程中使用到的一些对象
<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork"/>
2)默认包,包名叫struts-default(我们写的package必须继承默认包,才可使用该默认包下的功能)
<package name="struts-default" abstract="true">
<package name="default" extends="struts-default" namespace="">
2.1)常用跳转类型:
redirect: 重定向到页面
dispatcher: 转发到页面
redirectAction: 重定向到Action
chain: 转发到Action
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
2.2)声明拦截器(Interceptor):struts2默认的拦截器(32个),完成strutrs2的核心功能(请求封装,文件上传,国际化,后台数据校验..)
过滤器Filter:可以过滤任何类型的请求(html、servlet、jsp)和响应。加入通用的代码逻辑
拦截器Intercptor:sturts2特有功能,只能过滤Action。在执行Action的时候加入通用的代码
2.3)声明拦截器栈 (<interceptor-stack name="basicStack">)
默认拦截器:<interceptor-stack name="defaultStack"> (18个拦截器)
2.4)默认包当前使用的拦截器:
<default-interceptor-ref name="defaultStack"/>
2.5)当前默认包下的默认Action
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
struts.xml文件详解:开发者自行配置的业务配置文件
1)包package:用于管理Action,一般可以按模块划分包
package: 代表一个包。管理action配置。在用一个包下面不能有同名的action
name:包名,在一个项目中不能出现同名的包。
extends: 继承。如果一个包继承另一个包,就会把父包的功能继承下来
namespace: 名称空间。区分不同的包的访问路径。默认值“/”
用户访问Action的路径搜索规则:http://localhsot:8080/project/namespace/action的name
abstract: 表示当前包是否抽象。如果当前包是抽象包,那么不能含有action。
抽象包中一般用来定义拦截器,公共视图,不做具体的业务。
2) Action和result的配置
action配置:
name: action的名称。用于访问该Action的路径
class: Action业务对象的类名。一定是全名(包名+类名),struts2是用反射构造Action对象
method: 执行的业务方法。不写默认值execute
result配置:
name: 视图的标记。在一个Action中名称不要重复
type: 跳转的类型。
redirect:重定向
dispatcher: 转发(默认值)
redirectAction: 重定向到Action
chain: 转发到Action。可以在不同Action中通过request共享数据
stream: 用在下载文件的时候。
文本内容: 跳转到的页面或者Action
3) 可以通过划分不同的xml文件来管理package
<!-- 包含读取其他xml文件,声明的顺序就是读取的顺序 -->
<include file="config/struts-action.xml"></include>
<include file="config/struts-path.xml"></include>
struts2的配置相关:Action三种使用方式-路径通配符-常量配置-全局视图配置和默认配置-Action的属性注入
1) struts2使用Action方法:不实现继承/实现Action接口/继承ActionSupport(常用)
/**
* 第一种方式:不需要实现或继承任何接口或类
*/
public class UserAction1 {
public String login()throws Exception{
System.out.println("UserAction1.login()");
return "success";
}
}
/**
* 第二种方式:实现Action接口
* 1) 定义了默认的execute方法的标准
* 2) 提供了项目中常用的视图标记
*/
public class UserAction2 implements Action {
public String login() throws Exception {
System.out.println("UserAction2.login()");
return SUCCESS;
}
public String execute() throws Exception {
return null;
}
}
/**
* 第三种方式:继承ActionSupport类(推荐使用)
* 1)提供了常用的视图标记
* 2)提供了数据校验功能
*/
public class UserAction3 extends ActionSupport{
public String login() throws Exception{
System.out.println("UserAction3.login()");
return SUCCESS;
}
}
2) 路径通配符
<!-- 一个模块(Action对象)使用一个action配置:减少action的配置 -->
<!-- * (星号):表示路径的通配符
获取通配符的内容:{1}(表示获取第一个通配符的实际内容)-->
<!--
<action name="user_*" class="com.hfxt.b_path.UserAction" method="{1}">
<result name="{1}">/{1}.jsp</result>
</action> -->
<!-- 多个模块使用一个action配置:第一个*代表模块,第二个代表方法
User_login -->
<action name="*_*" class="com.hfxt.b_path.{1}Action" method="{2}">
<result name="{2}">/{1}/{2}.jsp</result>
</action>
2) struts2常量配置:struts-core.jar、default.properties常量文件
struts.xml文件中修改常量值 <constant name="" value=""/>
<!-- 指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 -->
<constant name="struts.i18n.encoding" value="UTF-8"/>
<!--自定义后缀修改常量-->
<constant name="struts.action.extension" value="do"/>
<!--设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭-->
<constant name="struts.serve.static.browserCache" value="false"/>
<!--当struts配置文件修改后,系统是否自动重新加载该文件,默认为false(开发环境下使用)-->
<constant name="struts.configuration.xml.reload" value="true"/>
<!--开发模式下使用,这样可以打印出更详细的错误信息-->
<constant name="struts.devMode" value="true" />
<!--默认的视图主题-->
<constant name="struts.ui.theme" value="simple" />
<!--与spring集成时,指定由spring负责action对象的创建-->
<constant name="struts.objectFactory" value="spring" />
<!--该属性设置Struts2是否支持动态方法调用,该属性的默认值是true-->
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
<!--上传文件的大小限制-->
<constant name="struts.multipart.maxSize" value=“10701096"/>
3) 全局视图和action默认配置:
<!-- 全局结果: 当前包下的所有action共享视图
当action中也有相同名称的视图,那么action的局部视图会覆盖全局视图 -->
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<!-- 异常映射: 程序出现异常是跳转到的结果视图 -->
<global-exception-mapping>
<exception-mapping result="error" exception="java.lang.RuntimeException">
</exception-mapping>
</global-exception-mapping>
<!--action默认配置:name(必填)、class(可选,默认ActionSupport类)、method(可选)
result:name(可选,默认success)、type(可选,默认dispatcher) -->
<!-- 全部使用默认配置的action的作用:专门用于转发到WEB-INF下的页面 -->
<action name="user">
<result name="success">/WEB-INF/jsp/login.jsp</result>
</action>
4) Action属性注入: Action对象把经常改变的参数提取到配置文件中,就可以使用属性注入的方法
1)在Action类中声明一个成员变量,用于接收xml配置文件传入内容
2)在Action类提供一个该变量的setter方法,该方法接收了xml配置的内容
//1)在action中提供一个属性
private String iocStr;
//2)提供属性的setter方法,用于外部的action的参数进行注入
public void setIocStr(String iocStr) {
this.iocStr = iocStr;
}
3)在对应的struts.xml文件中,找到对应的action对象的配置,然后在action中使用<param name=""></param> 这个标签来向Action对象的属性注入内容
<action name="ioc" class="com.hfxt.d_ioc.IocAction" method="IocMethod">
<!--3)配置往Action对象的属性注入内容(只要有setter都可以使用param进行注入)
param:
name: setter方法名 setIocStr -> iocStr
-->
<param name="iocStr">”注入的字符串值”</param>
<result>/login.jsp</result>
</action>
struts2核心业务功能:数据共享(三种方式)-请求数据封装-类型转换(自定义)-文件上传和下载、国际化-数据验证-模型驱动
1) (域对象)数据共享三种方式: ServletActionContext/ActionContext/Action
1. ServletActionContex得到servlet的api(依赖servlet)
HttpServletRequest getRequest():获取request对象
HttpSession getRequest().getSession():获取session对象
ServletContext getServletContext():获取ServletContext对象
2. ActionContext得到操作域对象数据的Map集合(不依赖servlet,方法局部)
ActionContext ac = ActionContext.getContext();
Map<String,Object> requestMap = ac.getContextMap();
Map<String,Object> seesionMap = ac.getSession();
Map<String,Object> contextMap = ac.getApplication();
requestMap/seesionMap/contextMap.put(“key”,value);
3. Action类实现RequestAware,SessionAware,ApplicationAware接口(action全局)
//实现提供的方法:获取操作域对象数据的Map集合
public UserAction extends ActionSpport implements RequestAware,SessionAware,ApplicationAware{
private Map<String,Object> requestMap/SessionMap/contextMap;
public void setRequest/setSession/setApplication(Map<String,Object> request/session/application){
this.requestMap/SessionMap/contextMap = request/session/application;
}
requestMap/SessionMap/contextMap.put(“key”,value);
}
2) 请求参数封装:属性注入(setter)-JavaBean-ModelDriven
表单参数(传值)>Action属性/JavaBean对象(赋值)>JSP页面(取值)
1. 基本数据类型接收参数(action中提供setter方法)
//参数赋值(注入方式)
private String name;
private String password;
//参数通过这个set方法注入到Action中
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
2. javabean类型接收参数(action提供getter和setter)
public class UserAction extends ActionSupport{
//使用一个javabean对象接收
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
用户名: <input type="text" name="user.name"/><br/>
密码: <input type="password" name="user.password"/><br/>
Action接受参数的三种方式 | |||
| 属性方式 | JavaBean方式 | ModelDriven方式 |
form中上传参数 | form中元素name取值属性名 | form中元素name取值对象名.属性名 | form中元素name取值属性名 |
Action中接收参数 | 为Action添加实体属性以及setter方法 | 对象表单参数的属性及对应JavaBean对象的setter、getter方法 | Action实现ModelDriven接口,重写getModel() |
页面中取值 | ${username} <s:property value=”属性名”/> | name=”item.username” ${item.username} <s:property value=”对象名.属性名”/> | <s:property value=”属性名”/> |
3) 类型转换(自定义类型转换器,继承StrutsTypeConverter类)
默认情况下:基本数据类型可以直接从String转换,日期只能转yyyy-MM-dd类型
/**
* 从页面的数据到服务器的类型转换
* 参数一 context: 值栈上下文对象
* 参数二 values: 从页面传递过来的参数值
* 参数三 toClass: 转换到的类型。String->java.util.Date
*/
public Object convertFromString(Map context,String[] values,Class toClass)
/**
* 从服务器到页面的类型转换
*/
public String convertToString(Map context, Object o) {
return null;
}
绑定自定义转换器的方式:
局部绑定(只能绑定一个Action):在action同一个包下建立ActionName-conversion.properties
user.birth=com.hfxt.g_convert.MyDateConverter
全局绑定(绑定整个项目多个Action):在src下建立xwork-conversion.properties
java.util.Date=com.hfxt.g_convert.MyDateConverter
4) 上传与下载:
文件上传:
1.三个条件:表单有file、post提交、enctype="multipart/form-data"
<s:form action="Upload" method="post" enctype="multipart/form-data">
<input type="file" name="attach" />
<input type="submit" value="上传" />
</s:form>
2.在Action中接收文件内容:
public class UploadAction extends ActionSupport {
单文件:
File attach; (attach是file表单的name属性)
String attachContentType; 文件类型
String attachFileName; 文件名称
多文件:
File[] attach;
String[] attachContentType;
String[] attachFileName;
//属性设置setter方法:上传文件内容赋值
//文件保存
String savePath = ServletActionContext.getServletContext()
.getRealPath("/"); //获取路径
FileUtils.copyFile(attach,new File(savePath+attachFileName));
}
3.配置struts.xml,拦截器会自动接收上传的文件
<!-- 限制上传文件的大小和类型 -->
<constant name="struts.multipart.maxSize" value="100000"></constant>
<action name="upload" class="com.hfxt.web.action.UploadAction"
method="upload">
<interceptor-ref name="fileUpload">
<!-- 限制文件类型 -->
<param name="allowedTypes">image/jpg,image/png</param>
<!-- 限制文件后缀 -->
<param name="allowedExtensions">jpg,png</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result>/upload_view.jsp</result>
<result name="upload">/upload.jsp</result>
</action>
文件下载:
<action name="down_*" class=" com.hfxt.upload_down.DownAction ">
<!-- 文件下载视图类型是stream -->
<result type="stream">
<!-- 返回给浏览器的文件类型,返回通用的二进制 -->
<param name="contentType">xxx</param>
<!-- 返回给浏览器的输入流 -->
<param name="inputName">Action中定义获取输入流的方法(方法名)</param>
<!-- 浏览器下载资源的方式 -->
<param name="contentDispostion">xxx</param>
<!-- 缓存大小 -->
<param name="bufferedSize">1024</param>
</result>
</action>
//在Action对象中提供一个对应的获取输入流的方法
public InputStream getInputStream(){
FileInputStream fis = new FileInputStream(new File(serverPath+name));
return fis;
}
拦截器interceptor(拦截Action资源)-值栈value stack(显示数据)
拦截器:只能拦截Action资源;拦截完Action,添加逻辑代码
1)自定义拦截器: 实现Interceptor接口
init(): 在创建拦截器对象的时候,拦截器对象在加载web应用时创建。
interceptor(): 每次访问action的业务方法的时候调用
destory(): 拦截器对象销毁的时候调用。web应用重新部署或web服务器停止
<!-- Struts.xml定义使用拦截器: 调用默认拦截器(defaultStack) -->
<package name="inter" extends="struts-default" namespace="/inter">
<!-- 定义拦截器 -->
<interceptors>
<interceptor name="inter1" class=" com.hfxt.interceptor.MyInterceptor1"></interceptor>
</interceptors>
<!-- 全局作用的使用拦截器 -->
<default-interceptor-ref name="inter1"></interceptor-ref>
<action name="user_*" class="com.hfxt.interceptor.UserAction" method="{1}">
<!-- 局部作用的使用拦截器 -->
<interceptor-ref name="inter1"></interceptor-ref>
<result>/index.jsp</result>
</action>
<!-- 引入自定义拦截器 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
</package>
2)拦截器栈:当前action同时被多个拦截器拦截,就使用拦截器栈
<!-- 拦截器栈 myStack -->
<interceptor-stack name="myStack">
<interceptor-ref name="Interceptor1"></interceptor-ref>
<interceptor-ref name="Interceptor2"></interceptor-ref>
<!-- 默认拦截器 defaultStack -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
<!-- 默认拦截器栈 defaultStack: -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- struts-default.xml:默认拦截器 -->
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">
dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*
</param>
</interceptor-ref>
</interceptor-stack>
值栈:是struts2的数据存取的核心;Struts2使用OGNL作为默认的表达式
OGNL表达式(Object Graph Navigation Langage,对象图导航语言)>OGNLContext对象(存取数据)>OgnlValueStack值栈对象(存取数据List/Map)>Struts2标签
EL表达式:获取域对象的数据。不能存放数据,不能调用方法
Ognl表达式:获取域对象的数据。可以存放数据,可以调用方法
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
3、支持赋值操作和表达式串联,如price=100, discount=0.8,
calculatePrice(),这个表达式会返回80;
4、访问OGNL上下文(OGNL context)和ActionContext;
5、操作集合对象
Struts2标签:逻辑标签(数据标签|控制标签)-UI标签-Ajax标签
<%@ taglib uri="/struts-tags" prefix="s"%>
逻辑标签:
迭代: <s:iterator value="ognl表达式" var="" status="">
赋值: <s:set var="" value="ognl表达式"/>
获取: <s:property value="ognl表达式"/>
判断: <s:if/> <s:elseif/> <s:else/>
UI标签:数据回显功能
<s:form/> -> <form>
<s:textfield/> -> <input type="text"/>
<s:password/> -> <input type="password"/>
<s:checkbox/> -> <input type="checkbox"/>
<s:checkboxlist list="多个值"/> -> 多个<input type="checkbox"/>
<s:radio list="多个值"/> -> 多个<input type="radio"/>
<s:select list="多个值"/> -> <select>多个<option/></select/>
Ajax标签:dateimepicker
1) ognl表达式:存取数据(Ognl存取数据的核心:OgnlContext对象)
OgnlContext对象数据结构:
根对象 Object root: 直接访问属性
非根对象 Map values: 带#,根据key获取value
//struts2项目中导入ognl.jar包来实现支持ognl表达式
//1)创建一个OgnlContext对象
OgnlContext context = new OgnlContext();
//2a)把user对象存入OgnlContext对象
context.put("user", user);//往OgnlContext的非根对象存数据
//3a)使用Ognl表达式从OgnlContext对象取出数据
Object ognlObj = Ognl.parseExpression("#user.name");//表达式对象
Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法
//2b)把user对象存入OgnlContext对象
context.setRoot(user);往OgnlContext的根对象存数据
//3b)使用Ognl表达式从OgnlContext对象取出数据
Object ognlObj = Ognl.parseExpression("name");//表达式对象
Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法
System.out.println(result);
<%@ taglib uri="/struts-tags" prefix="s"%>
<!-- EL表达式 -->
<%-- ${username } --%>
<%-- ${item.username } --%>
<!-- Struts2标签 -->
<!-- 访问根对象:对象.属性名 -->
<s:property value="item.username" />
<!-- 访问非根对象:#对象.属性名 -->
<s:property value="#session.loginUser.username" />
2) struts2值栈对象:ValueStack(Struts2存取数据的核心:实现类OgnlValueStack,本质OgnlContext)
ValueStack数据存储结构:List栈(根栈)-Map栈(非根栈)
OgnlValueStack对象数据结构:
List<Objet> root: 根对象(List栈)
OgnlContext对象:
Object root: 根对象 不用带#,直接访问属性
Map values: 非根对象(Map栈) 带#,根据key获取value
OgnlValueStack对象分为两部分存储数据:List栈-Map栈
List对象栈:Action对象,Provider对象,ValueStack.push(obj)
Ognl表达式访问List栈(不要#,直接写属性名):依次搜索
第一个对象:找user,找到返回,找不到往下一个对象找
第二个对象:找user,找到返回,找不到往下一个对象找
所有对象找完,都没有,就返回空
Map栈:request域的Map,session域的Map,application域的Map,attr的Map,paramter参数的Map
Ognl表达式访问Map栈(必须要#,根据key找value):
request域的Map : #request.user
session域的Map : #session.user
application域的Map : #application.user
attr的Map, : #attr.uesr
paramter参数的Map : #parameter.user
用户访问Action对象业务方法:ActionContext对象>OgnlValueStack对象(List/Map)>Action对象
//1)获取ActionContext对象
ActionContext ac = ActionContext.getContext();
List<User> list = new ArrayList<User>();
list.add(new User("jacky",30));
list.add(new User("rose",40));
list.add(new User("lucy",50));
ac.getContextMap().put("userList", list);
Map<String,User> map = new HashMap<String,User>();
map.put("100", new User("mark",20));
map.put("101", new User("maxwell",30));
map.put("102", new User("lily",40));
ac.getContextMap().put("userMap", map);
//往域对象存放数据
ac.getContextMap().put("request_data", "request_data");
ac.getSession().put("session_data", "session_data");
ac.getApplication().put("application_data", "application_data");
//2)从ActionContext对象获取OnglValueStack对象
ValueStack vs = ac.getValueStack();
//3)查看OnglValueStack对象的结构
//往OgnlValueStack的根对象(List栈)存放数据
vs.push(user);//往List栈 的栈顶
vs.pop(); //从List栈中 取出元素(栈顶元素)
<%-- 1) 取出List栈的数据 --%>
<s:property value="user.name"/> - <s:property value="user.age"/> <br/>
<%--查看值栈的所有数据 --%>
<%--2) 取出Map栈的数据 --%>
<s:property value="#request.request_data"/><br/>
<%--值栈对象是通过request域专递到页面,可以直接忽略#request去取request域的数据 --%>
<s:property value="#request_data"/><br/>
<s:property value="#session.session_data"/><br/>
<s:property value="#application.application_data"/><br/>
<%-- #attr:三个域中从小到大搜索数据: #request->#session->#application --%>
<s:property value="#attr.session_data"/><br/>
<s:property value="#parameters.name"/><br/>
<hr/>
${session_data }
<hr/>
<%-- 遍历集合 :List--%>
<s:iterator value="#request.userList" var="user">
姓名: <s:property value="#user.name"/> - <s:property value="#user.age"/><br/>
</s:iterator>
<hr/>
<%-- 遍历集合:Map --%>
<s:iterator value="#request.userMap" var="entry">
编号: <s:property value="#entry.key"/> - 姓名: <s:property value="#entry.value.name"/> - <s:property value="#entry.value.age"/><br/>
</s:iterator>
<s:debug></s:debug>
struts2核心功能:国际化-数据验证-模型驱动
struts2中简化国际化步骤:
1)准备不同国家的资源包
中国: message_zh_CN.properties
user=用户名
美国: message_en_US.properties
英国: message_en_GB.properties
2)在struts.xml文件中(修改)指定资源包加载路径的常量
struts.custom.i18n.resources=message
3)在页面上使用资源包的内容
<s:text name="user"/>
struts2数据验证:提供给开发者进行表单数据的后台数据验证的功能
1)Action类继承ActionSupport(为了实现Valiateable接口)
2)Action类覆盖validate方法(验证所有方法)
public void validate() {
//在这里写表单数据验证的逻辑
//System.out.println("调用了validate方法");
if(user.getName()==null || user.getName().equals("")){
//用户名为空
//把错误信息放入错误信息Map集合
super.addFieldError("user.error.requried", "用户名不能为空!");
}
if(user.getPassword()==null || user.getPassword().equals("")){
//密码为空
//把错误信息放入错误信息Map集合
super.addFieldError("password.error.requried", "密码不能为空!");
}
}
3)在struts.xml文件中对应的action配置加上input视图,然后struts2就会自动把错误信息转发到input视图的页面上去
4)在input视图页面上,打印出错误信息
<s:fielderror></s:fielderror>
模型驱动:
请求数据封装:
方式一: 表单:name -> 基本数据类型: String name
方式二: 表单:user.name -> javabean数据类型:User user (User:String name)
方式三(模型驱动方式):表单:name -> javabean数据类型:User user (User:String name)
public class UserAction extends ActionSupport implements ModelDriven<User>{
//注意:使用模型驱动的方式,存放数据的模型引用不能为空
private User user = new User();
//该方法struts2可以把值栈中的请求参数封装到User对象
public User getModel() {
return user;
}
}
Spring
Spring框架:轻量级的企业级开源框架,面向Bean的编程
Spring体系结构:
功能模块:Core Container>AOP>Data>Access/Integration>Web
Ioc:Inversion of Control,控制反转 / 依赖注入(DI:Dependency Injection)
实现业务层与数据访问层解耦合,将组件对象C的控制权从代码本身转移到外部容器:
A --工厂BFactory-- B (IB接口 B1 B2 B3)
public class A {
IB b = BFactory.getInstance();
}
Spring配置步骤:
- 添加核心jar包:spring-beans|spring-context|spring-core|spring-expression
commons-logging.jar 【单独下载】
spring-beans.RELEASE.jar 【spring源码, bean节点管理】
spring-context.RELEASE.jar 【spring上下文类】
spring-core.RELEASE.jar 【IOC容器】
spring-expression.RELEASE.jar 【spring表达式】
- 添加配置文件applicationContext.xml:
<beans xmlns="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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 创建对象 -->
<!-- userDaoImpl userDao = new UserDaoImpl() -->
<bean id="userDao" class="com.hfxt.dao.impl.UserDaoImpl"></bean>
<!-- userService对象注入userDao对象 -->
<!-- 设值注入 scope默认singleton(单例) -->
<bean name="userService" class="com.hfxt.service.impl.UserServiceImpl" scope="prototype">
<!-- ref注入对象 value注入值 -->
<property name="UserDao" ref="userDao"></property>
<property name="name" value="ftmy"></property>
<!-- 注入List集合 -->
<property name="testList">
<list>
<value>aaa</value>
<value>bbb</value>
</list>
</property>
</bean>
<!-- 构造注入 -->
<bean name="userService" class="com.hfxt.service.impl.UserServiceImpl">
<constructor-arg ref="userDao"></constructor-arg>
</bean>
<!-- p标签注入方式 -->
<bean name="userService" class="com.hfxt.service.impl
.UserServiceImpl" p:name="ftmy" p:userDao-ref="userDao" ></bean>
</beans>
- 在要注入的类添加注入接口:set方法注入/构造注入
UserDao userDao;
/**
* 注入接口:设值注入
* @param userDao
*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
/**
* 构造注入
*/
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
Test.java:
public static void main(String[] args) {
/*
* 获取注入对象
*/
//加载spring配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"applicationContext.xml");
//getBean()方法获取对应id或name的Bean对象
UserService userService = (UserService) ctx.getBean("userService");
userService.addUser();
/*
UserService userService1 = (UserService) ctx.getBean(
"userService");
UserService userService2 = (UserService) ctx.getBean(
"userService");
System.out.println(userService1 == userService2);//同一对象
*/
}
Spring IOC容器
配置文件详解:创建bean细节
<!-- 把对象加入IOC容器 -->
<!--
细节1:
id 与 name:
id 不能以数字开头,不能含有特殊符号, 不能有空格、逗号等; id 不能重复!
name 可以以数字开头,可以有特殊符合,如果name值重复,编译没有问题但运行报错!
<bean id="user" name="user2,user3 user4" class="cn.itcast.a_config.User"></bean>
<bean name="user5" class="cn.itcast.a_config.User"></bean>
<bean id="user6" class="cn.itcast.a_config.User"></bean>
<bean id="user6" class="cn.itcast.a_config.User"></bean>
-->
<!-- 细节2: (单例/多例) -->
<!--
scope="singleton" 默认表示单例!
prototype 多例
init-method="" 在创建完对象之后执行初始化方法
destroy-method="" 在调用容器类的destroy()方法时候,对单例的对象有效!
lazy-init="true" 延迟初始化 / 这个属性的设置只对单例有影响,对多例没有任何影响!
单例的对象默认是在创建容器的时候就创建所有单例的对象,如果希望在第一次访问的时候创建单例的对象,就设置延迟初始化
Bean生命周期:
bean在xml中配置,
singleton 单例
1) 创建对象
如果有配置延迟初始化,
lazy-init=true 如果单例的对象有配置延迟初始化, 在创建容器之后,在第一次从容器获取对象的时候
创建单例的对象!
如果没有配置或延迟初始化为默认值, 单例的对象会在创建容器的时候创建对象
2) 执行初始化方法 , init-method配置的方法会执行
3) 调用容器destroy() 方法时候,容器在销毁单例对象的实例的时候,会调用destroy-method对应的方法
此时bean对象会被销毁!
prototype 多例
1) 每次在从容器获取对象的时候,都会创建新的对象
2) 每次创建完对象后,就执行初始化方法
3) java回回收不用资源(jvm gc)
-->
<bean id="user"
class="cn.itcast.a_config.User"
init-method="init"
destroy-method="destroy_"
lazy-init="false"
scope="prototype"></bean>
</beans>
自动装配:默认no|byName|byType|constructor
全局装配:default-autowire="byName"
<bean name="userService" class="com.hfxt.service.impl.UserServiceImpl" autowire="byName" >
</bean>
IoC两大关键技术一个设计模式:JDOM(DOM解析)|反射机制|工厂模式(单例模式)
Bean作用域:singleton(默认)、prototype、request、session
处理对象的依赖关系:
给对象属性赋值(DI, 依赖注入),几种方式:
1) 构造函数赋值
2) set 方法注入值
* 普通字段赋值
* 集合属性 (list/map/property)
注解总结:
@Component 表示一个组件(类),把当前组件加入ioc容器
加入容器的组件的名称默认是类名第一个字母小写
@Component(“”) 指定加入ioc容器的组件类的类名
@Repository 标识是一个持久层的组件
@Service 标识是一个业务逻辑层的组件
@Controller 标识是一个控制层的组件
@Scope("prototype") 指定对象单例/多例
@Resource 1. 默认根据修饰的字段名称会取ioc容器找对象自动注入找到后注入
2. 如果名称没有找到,再根据类型查找 找到后就立刻注入
如果改类型在ioc容器中有多个对象,报错!
3. 根据类型也没有找到对象,报错!
@Resource(name =””) 会根据指定的名称去容器找对象自动注入
创建对象的几种方式:
1) 调用无参数构造器
2) 调用有参数构造器
3) 工厂
* 静态方法
<bean id=”’ class=”” factory-method=””/>
* 非静态方法
<bean id=”factory” class=”..”>
<bean id=”” factory-bean=” factory” factory-method=”实例方法” />
4) 反射
AOP(Aspect Oriented Programming):面向切面编程(面向方面编程), 关注点代码(重复执行的代码,关注点代码形成的类叫做切面)与业务代码分离
使用Aop开发步骤:
1. 引入aop 相关 jar文件
(aspectj在spring之前,面向切面开发的公用组件)
aopalliance.jar [spring-framework-2.5.6\lib\aopalliance]
aspectjrt.jar [spring-framework-2.5.6\lib\aspectj]
aspectjweaver.jar [spring-framework-2.5.6\lib\aspectj]
spring-aop-3.2.5.RELEASE.jar [Spring3.2源码]
2. 引入aop名称空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.itcast.e_aop_anno"></context:component-scan>
<!-- 开启aop注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
4. 使用Aop相关注解
@Aspect 指定一个类为切面类
(切面类也需要实例化)(切面类中的方法,也叫做通知)
@Before 前置通知 【在执行目标对象方法之前执行】
@After 后置通知 【在执行目标对象方法之后执行】
@AfterReturning 返回后通知 【在执行目标对象方法结束后执行, 出现异常不执行】
@AfterThrowing 异常通知 【在执行目标对象方法出现异常时候执行】
@Around 环绕通知 【环绕目标方法执行】
@Pointcut 定义一个切入点表达式变量(后面使用这个切入点表达式的时候,直接引用方法名即可)
Spring生成代理对象的过程:
1. 创建容器对象的时候, 根据“切入点表达式”拦截的类,生成代理对象;
2. 如果目标对象有实现接口,使用jdk代理!
3. 如果目标对象没有实现接口,使用cglib代理!
4. 从容器获取代理后的对象
5. 执行代理对象的方法,在运行时期,动态植入“切面”类中的“通知”!
aop编程
1. 引入aop 相关jar文件
2. bean.xml 引入aop名称空间
3. Aop配置:XML配置方式
<beans
<!-- dao实例加入容器 -->
<bean id="userDao" class="cn.itcast.f_aop_xml.UserDao"></bean>
<!-- 实例化切面类 -->
<bean id="aop" class="cn.itcast.f_aop_xml.TransactionAop"></bean>
<!-- Aop相关配置 -->
<aop:config>
<!-- 切入点表达式定义 -->
<aop:pointcut expression="execution(* cn.itcast.f_aop_xml.UserDao.*(..))" id="pt"/>
<!-- 切面配置 -->
<aop:aspect ref="aop">
<!-- 【环绕通知】 -->
<aop:around method="arroud" pointcut-ref="pt"/>
<!-- 【前置通知】 在目标方法之前执行 -->
<aop:before method="beginTransaction" pointcut-ref="pt" />
<!-- 【后置通知】 -->
<aop:after method="commit" pointcut-ref="pt"/>
<!-- 【返回后通知】 -->
<aop:after-returning method="afterReturing" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
4.AOP编程:主要是分离业务代码与关注点代码;关注点代码,写一次,在执行业务代码时候动态植入关注点代码
public void add(User user) {
Session session = null;
Transaction trans = null;
try {
session = HibernateSessionFactoryUtils.getSession(); 【关注点代码】
trans = session.beginTransaction(); 【关注点代码】
session.save(user); // 业务
trans.commit(); 【关注点代码】
} catch (Exception e) {
e.printStackTrace();
if(trans != null){
trans.rollback();
}
} finally{
HibernateSessionFactoryUtils.closeSession(session);
}
}
切入点表达式:拦截指定的类,生成代理对象
execution(
modifiers-pattern? 拦截的方法的访问修饰符
ret-type-pattern 方法返回类型,必须指定
declaring-type-pattern? 拦截的方法所在的类
name-pattern(param-pattern) 拦截的方法(以及方法的参数列表)
throws-pattern?) 方法声明的异常
代理模式Proxy:静态代理-动态代理(Jdk代理/Cglib子类代理)
类的单一职责原则(一个类只做一件事件),在不改变一个类的情况下,给这个类添加新的功能(被代理类-代理类)
静态代理:一个被代理类都必须有一个代理类
动态代理:可以根据被代理的对象来生成代理类的对象
Cglib代理:子类代理,当目标对象没有实现接口,就不能使用jdk提供的代理,可以以子类的方式实现,在运行时期动态在内存中构建一个子类对象的方法,从而对目标对象扩展,这种就是cglib代理!
Spring也支持cglib代理,核心包中已经包含此功能!
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class SecurityHandler implements InvocationHandler {
private Object delegate;//被代理类的对象
/**
* 根据被代理类的对象生成代理类的对象
* @param delegate
* @return
*/
public Object newProxy(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass()
.getClassLoader(), delegate.getClass().getInterfaces(), this);//参数:被代理类类加载器,被代理类接口,当前handler
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//System.out.println(method.getName());//打印方法名
Object o = method.invoke(delegate, args);
//Object o = addNewUser();//新的add方法(在不改变原先类的情况下,实现替换或增加新功能)
Security security = new Security();
security.checkSecurity();
return o;
}
public int addNewUser(){
System.out.println("--------addNewUser---------");
return 1;
}
}
public static void main(String[] args) {
SecurityHandler sh = new SecurityHandler();
//根据被代理类的对象来生成代理类的对象
UserDao userDao = (UserDao) sh.newProxy(new UserDaoImpl());
//所有调用转为对invoke()方法的调用
userDao.addUser();
}
AOP横切技术:核心关注点、横切关注点
增强(Advice)、切入点(Pointcut)、连接点(Joinpoint)
切面(Aspect)、代理(Proxy)、目标对象(Target)、织入(Weaving)
Advisor配置:
//实现前置增强处理接口MethodBeforeAdvice
public class ServiceBeforeAdvisor implements MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
//启动事务的代码
}
}
<bean id="serviceBeforeAdvisor" class="com.hfxt.aop"></bean>
<aop:config>
<aop:pointcut id="servicePointcut" expression="execution
(public * com.hfxt.service.*.*(..))" />
<!-- 在切入点织入增强处理 -->
<aop:advisor advice-ref="serviceBeforeAdvisor"
pointcut-ref="servicePointcut"/>
</aop:config>
实现AOP方式3种方式:配置、注解、实现接口
SSH
SSH整合:Struts2--Spring(粘合剂|对象注入)--Hibernate
Spring与Struts整合→Action创建交给Spring完成
Spring与Hibernate整合→SessionFactory创建,交给spring完成(管理事务)
添加struts2:
1、在lib下添加jar包(struts-2.3.16.3\apps\struts2-blank\WEB-INF\lib)
2、在src下添加struts.xml配置文件(apps\struts2-blank\WEB-INF\classes)
3、在web.xml中添加struts2核心控制器(过滤器组成)(apps\struts2-blank\WEB-INF\web.xml)
4、登陆界面
<!-- 修改默认布局 -->
<constant name="struts.ui.theme" value="simple"></constant>
<!-- 表单提交至/user命名空间的login方法 -->
<s:form action="login" namespace="/user">
用户名:<s:textfield name="item.username"></s:textfield> <br />
密码:<s:password name="item.password"></s:password> <br />
<s:submit value="登陆"></s:submit>
</s:form>
ActionContext.getContext().getSession().put("username", username);
欢迎您!<s:property value="#session.username"></s: property >
添加spring:
1、在lib下添加jar包(spring-framework-3.2.8.RELEASE\libs\)
2、在src下添加spring的配置文件applicationContext.xml
3、在web.xml中配置spring配置文件位置及配置一个监听器来加载spring的配置文件
<!-- Spring -->
<!-- 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>
整合struts2与spring:
1、添加一个整合的jar包(struts-2.3.4.1\lib\struts2-spring-plugin-2.3.4.1.jar)
2、在struts.xml中添加一个常量
<!-- 对象的创建工作交给spring -->
<constant name="struts.objectFactory" value="spring"></constant>
3、在spring的配置文件创建action类的bean,切记scope="prototype"
<!-- scope="prototype" -->
<bean name="userAction" class="com.hfxt.web.action.UserAction" scope="prototype">
</bean>
4、在struts.xml中把action的class改为spring中bean的id
<action name="login" class="userAction" method="login">
</action>
添加hibernate:
1、在lib下添加jar包
2、添加hibernate配置文件并配置(t38_mysql hibernate.show_sql)
3、添加实体类和实体类的映射文件
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"></generator>
</id>
整合spring与hibernate:
1、添加一些必须包(spring-jdbc|orm|tx)
2、创建dao层,在spring配置文件中加载hibernate配置文件,得到sessionFactory.把sessionFactory注入到userDao
3、创建service层并注入dao
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public User getUserByUsername(String username) {
String hql = "from User where username=?";
List<User> list = super.getHibernateTemplate().find(hql, username);
return list != null && list.size() > 0 ? list.get(0) : null;
}
}
<!-- 加载hibernate配置文件 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3
.LocalSessionFactoryBean">
<property name="configLocations">
<value>classPath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- dao -->
<!-- sessionFactory注入到userDao -->
<bean id="userDao" class="com.hfxt.dao.impl.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- service -->
<bean id="userService" class="com.hfxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- Action(注入userService) -->
<!-- scope="prototype" -->
<bean id="userAction" class="com.hfxt.web.action.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
4、修改aciton等
ssh整合改:BaseDao--Dao--Service--Action
源文件夹newSourceFolder:src/code src/config
开闭原则:Dao层|IBaseDao接口-BaseDao实体类--BaseService(存放注入接口或扩展功能)--BaseAction
异常处理:
Exception>ServiceException>DaoException>HibernateDaoSupportException
拆分配置文件:
Spring配置文件拆分:
applicationContext.xml
<!-- connection-->
<!-- 加载属性文件:jdbc.properties(键值对) -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- dataSource 数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0
.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 指定连接数据库连接池的最大连接数 -->
<property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
<!-- 指定连接数据库连接池的最小连接数 -->
<property name="minPoolSize" value="${jdbc.minPoolSize}"/>
<!-- 指定连接数据库连接池的初始化连接数 -->
<property name="initialPoolSize"
value="${jdbc.initialPoolSize}">
</property>
<!-- 指定连接数据库连接池的连接的最大空闲时间 -->
<property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
</bean>
<!-- sessionFactory -->
<bean id="sessionFactory" lass="org.springframework.orm
.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
${jdbc.dialect}
</prop>
<prop key="hibernate.show_sql">
${hibernate.show_sql}
</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/hfxt/entity/User.hbm.xml</value>
</list>
</property>
</bean>
<!-- 配置声明式事务 -->
<!-- 创建事务管理器 -->
<bean id="myTransactionManager" class="org.springframework.orm
.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 创建一个事务advice -->
<tx:advice id="txAdvice" transaction-manager="myTransactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"></tx:method>
<tx:method name="del*" propagation="REQUIRED"></tx:method>
<tx:method name="update*" propagation="REQUIRED"></tx:method>
<tx:method name="do*" propagation="REQUIRED"></tx:method>
<tx:method name="*" propagation="SUPPORTS" read-only="true">
</tx:method>
</tx:attributes>
</tx:advice>
<!-- aop -->
<aop:config proxy-target-class="true">
<aop:pointcut id="bizMethods" expression=
"execution(* com.hfxt.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref=
"bizMethods"></aop:advisor>
</aop:config>
daoContext.xml
<!-- 导入公共配置文件 -->
<import resource="applicationContext.xml"/>
<!-- dao -->
<bean id="baseDao" class="com.hfxt.dao.impl.BaseDao" abstract="true">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="userDao" class="com.hfxt.dao.impl.UserDaoImpl" parent=
"baseDao">
</bean>
serviceContext.xml
<!-- 导入dao层配置文件 -->
<import resource="daoContext.xml"/>
<!-- service -->
<bean id="baseService" class="com.hfxt.service.impl.BaseService" abstract="true">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userService" class="com.hfxt.service.impl.UserServiceImpl" parent="baseService">
</bean>
actionContext.xml
<!-- 导入service层配置文件 -->
<import resource="serviceContext.xml"/>
<bean id="baseAction" class="com.hfxt.web.action.BaseAction" abstract="true">
<property name="userService" ref="userService"></property>
</bean>
<!-- scope="prototype" -->
<bean id="userAction" class="com.hfxt.web.action.UserAction" scope="prototype" parent="baseAction">
</bean>
Struts配置文件拆分:struts.xml(公共部分)--struts-admin.xml
日志:debug--info--warn--error
web.xml:
<!--如果不定义webAppRootKey参数,那么webAppRootKey是缺省的"webapp.root"-->
<context-param>
<param-name>webAppRootKey</param-name>
<!-- 这里的t38是http://localhost:8080/t38/ -->
<!-- 而root是系统开发目录中t38.root-->
<param-value>t38.root</param-value>
</context-param>
<!--由Sprng载入的Log4j配置文件位置-->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<!--Spring默认刷新Log4j配置文件的间隔,单位为millisecond-->
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<!-- Web 项目 Spring 加载 Log4j 的监听 -->
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
log4j.properties:
<!-- 取消显示多余信息 debug->info -->
log4j.logger.xxx=INFO
<!-- 添加log-->
public Logger log = LoggerFactory.getLogger(this.getClass());
log.info("{} login success!!!"+item.getUsername());
登陆:jQuery>ajax>json>Map集合(type="json")
导入jquery和验证框架:${jquery_js} ${validate_js } ${validate_css }
taglibs.jsp:Basejsp
<%-- system values --%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<c:set var="siteName" value="******系统" />
<%-- css file define--%>
<c:set var="index_css" value="<link href='${ctx}/css/index.css' rel='stylesheet' type='text/css' />"/>
<c:set var="validate_css" value="<link href='${ctx}/css/validate.css' rel='stylesheet' type='text/css' />"/>
<%-- js file define --%>
<c:set var="jquery_js" value="<script type='text/javascript' src='${ctx}/js/jquery-1.7.js'></script>" />
<c:set var="validate_js" value="<script type='text/javascript' src='${ctx}/js/jquery.validate.js'></script>" />
//表单验证
$(function() {
//定义规则
$("#login_form").validate({
rules : {
"item.username" : "required",//name属性:值
"item.password" : {
"required" : true,
"minlength" : 3
}
},
messages : {
"item.username" : "用户名不能为空",
"item.password" : {
"required" : "密码不能为空",
"minlength" : "密码长度不能小于3位"
}
}
});
$("#btnLogin").click(function() {
/* //非框架验证
if ($.trim($("#username").val()) == "") {
alert("用户名不能为空");
return;
}
if ($.trim($("#password").val()) == "") {
alert("密码不能为空");
return;
} */
//validate框架验证
$(this).attr('disabled',"true");//禁用登陆按钮-防止多次提交请求
if ($("#login_form").valid()) {
var url = "${ctx}/user/ajaxLogin.action";
$.post(
url,
{ "item.username" : $("#username").val(),
"item.password" : $("#password").val() },
function(data) {
$("#btnLogin").removeAttr("disabled");//启用按钮
if (data.retcode == "0") {
window.location.href="${ctx}/user/findUsers.action";
} else {
alert(data.retmsg);
}
}
);
}
});
});
<body>
<s:form id="login_form" action="login" namespace="/user">
用户名:<s:textfield name="item.username" id="username"/><br />
密码:<s:password name="item.password" id="password"/><br />
<input type="button" value="登陆" id="btnLogin" />
</s:form>
</body>
public String ajaxLogin(){
try {
item = userService.checkLogin(item.getUsername(),
item.getPassword());
if(item != null){
putToSession("loginUser",item);
log.info("{} login success!!!"+item.getUsername());
resultMap.put("retcode", RetCode.SUCCESS);
} else{
resultMap.put("retcode", RetCode.FAIL);
resultMap.put("retmsg", "用户名或密码错误!");
}
} catch (Exception e) {
log.error("method login bug:"+e);
resultMap.put("retcode", RetCode.UNKOWN_WRONG);
resultMap.put("retmsg", "未知错误!请重试或联系管理员!");
}
return SUCCESS;
}
<package name="default" extends="json-default" namespace="/user">
<action name="ajaxLogin" class="userAction" method="ajaxLogin">
<result type="json">
<param name="root">resultMap</param>
</result>
</action>
增删改查CRUD
// 删除:
public String deleteUser(){
try {
//验证item.id
boolean result = userService.deleteUser(item.getId());
if(result){
log.info("delete user success,id:{}!!!",item.getId());
resultMap.put("retcode", RetCode.SUCCESS);
} else{
resultMap.put("retcode", RetCode.FAIL);
resultMap.put("retmsg", "删除失败!");
}
} catch (Exception e) {
log.error("method deleteUser bug:"+e);
resultMap.put("retcode", RetCode.UNKOWN_WRONG);
resultMap.put("retmsg", "未知错误!请重试或联系管理员!");
}
return SUCCESS;
}
<action name="deleteUser" class="userAction" method="deleteUser">
<result type="json">
<param name="root">resultMap</param>
</result>
</action>
// 增加/修改:
udpateUser.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ include file="/common/taglibs.jsp" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>编辑/增加用户-${siteName }</title>
${jquery_js } ${jquery_form_js }
</head>
<body>
<s:form id="edit_form" action="doUpdateUser" namespace="/user">
<!-- add:id空值|update:id=item.id -->
<s:hidden id="id" name="item.id"></s:hidden>
<!-- struts2标签自动取得当前action的值(对象item的值) -->
用户名:<s:textfield name="item.username"></s:textfield><br/>
密码:<s:textfield name="item.password"></s:textfield><br/>
状态:<s:select name="item.status" list="#{1:'正常',2:'禁用' }">
</s:select><br />
<input type="button" value="保存" id="btnSave" />
</s:form>
</body>
</html>
<!-- 先加载body静态页面,再加载js,提升用户体验-->
<script type="text/javascript">
$(function(){
$("#btnSave").click(function(){
var id = $("#id").val();
var url;
if(id == ""){
url = "${ctx}/user/doAddUser.action";
}else{
url = "${ctx}/user/doUpdateUser.action";
}
//异步提交表单
var options = {
url : url,
success : callback,
type : 'post',
dataType : 'json'
};
$("#edit_form").ajaxSubmit(options);
});
});
function callback(data){
alert(data.retmsg);
if (data.retcode == "0") {
window.location.href="${ctx}/user/findUsers.action";
}
}
</script>
public String toAddUser(){
return SUCCESS;
}
public String toUpdateUser(){
try {
//对item.id做验证(设置拦截器,非登陆用户不能操作)
item = userService.getUserById(item.getId());
return SUCCESS;
} catch (Exception e) {
log.error("method toUpdateUser bug :{}",e);
return ERROR;
}
}
public String doAddUser(){
try {
// 验证item
item.setCreatetime(new Date());
userService.addUser(item);
log.info("add user success,id:{}!!!", item.getId());
resultMap.put("retcode", RetCode.SUCCESS);
resultMap.put("retmsg", "增加成功!");
} catch (Exception e) {
log.error("method doAddUser bug:" + e);
resultMap.put("retcode", RetCode.UNKOWN_WRONG);
resultMap.put("retmsg", "未知错误!请重试或联系管理员!");
}
return SUCCESS;
}
public String doUpdateUser(){
try {
//验证item
boolean result = userService.updateUser(item);
if(result){
log.info("udpate user success,id:{}!!!",item.getId());
resultMap.put("retcode", RetCode.SUCCESS);
resultMap.put("retmsg", "修改成功!");
} else{
resultMap.put("retcode", RetCode.FAIL);
resultMap.put("retmsg", "修改失败!");
}
} catch (Exception e) {
log.error("method doUpdateUser bug:"+e);
resultMap.put("retcode", RetCode.UNKOWN_WRONG);
resultMap.put("retmsg", "未知错误!请重试或联系管理员!");
}
return SUCCESS;
}
<action name="toAddUser" class="userAction" method="toAddUser">
<!-- /WEB-INF目录下只有转发才能访问|安全性 -->
<result>/WEB-INF/pages/updateUser.jsp</result>
</action>
<action name="toUpdateUser" class="userAction" method="toUpdateUser">
<result>/WEB-INF/pages/updateUser.jsp</result>
</action>
<action name="doAddUser" class="userAction" method="doAddUser">
<result type="json">
<param name="root">resultMap</param>
</result>
</action>
<action name="doUpdateUser" class="userAction" method="doUpdateUser">
<result type="json">
<param name="root">resultMap</param>
</result>
</action>
public int updateUser(User item) throws DAOException {
String hql = "update User set username=:username,password=:password
,status=:status where id=:id";
Map<String, Object> params = new HashMap<String, Object>();
params.put("username", item.getUsername());
params.put("password", item.getPassword());
params.put("status", item.getStatus());
params.put("id", item.getId());
return executeUpdate(hql, params);
}
分页和模糊查询:
<script type="text/javascript">
function jump(p,s){
//window.location.href="${ctx}/user/findUsers.action?pager
.currentPage="+p;
//var oForm = document.searchForm || document.forms[0];
with(document.searchForm){
elements["pager.currentPage"].value = p;
elements["pager.pageSize"].value = s;
submit();
}
}
</script>
<s:form name="searchForm" action="findUsers" namespace="/user">
<s:hidden name="pager.currentPage"></s:hidden>
<s:hidden name="pager.pageSize"></s:hidden>
<table style="width:70%;margin:0 auto;">
<tr>
<td>用户名:<s:textfield name="item.username"></s:textfield> </td>
<td>密码:<s:textfield name="item.password"></s:textfield> </td>
<td>状态:<s:select name="item.status" headerKey="0"
headerValue="请选择" list="#{1:'正常',2:'禁用' }">
</s:select> </td>
<td><s:submit value="查询"></s:submit> </td>
</tr>
</table>
<hr />
<table border="1" class="main_table">
<tr class="head_tr">
<td>序号</td>
<td>用户名</td>
<td>密码</td>
<td>状态</td>
<td>角色</td>
<td>创建时间</td>
<!-- 取消href默认行为-->
<td>操作/<a href="javascript:void(0);" class="add">增加</a>
</td>
</tr>
<!-- 当前遍历对象临时放入栈顶|根对象 -->
<s:iterator value="pager.pageRecords" status="s">
<tr>
<td><s:property value="(pager.currentPage-1)*pager.pageSize
+#s.index+1" /></td>
<td><s:property value="username" /></td>
<td><s:property value="password" /></td>
<td>
<s:if test="status == 1">
正常
</s:if>
<s:else>
<span style="color:red">禁用</span>
</s:else>
</td>
<td>
<s:property value="tbRole.rolename" />
</td>
<td>
<s:date name="createtime" format="yyyy-MM-dd HH:mm:ss" />
</td>
<td>
<a href="javascript:void(0);"class="update" rel=
"<s:property value="id"/>" >修改</a>
<a href="javascript:void(0);" class="delete" rel=
"<s:property value="id"/>" >删除</a>
</td>
</tr>
</s:iterator>
</table>
<hr />
</s:form>
<table style="width:98%;margin:0 auto;">
<tr>
<td style="text-align: left">
第<span style="color:red"><s:property value=
"pager.currentPage"/></span>/<s:property value="pager.pageCount" />页
共<s:property value="pager.total" />条
</td>
<td style="text-align: right">
<s:if test="pager.currentPage == 1">
首页
上一页
</s:if>
<s:else>
<a href="javascript:jump(1,<s:property value=
"pager.pageSize"/>)">首页</a>
<a href="javascript:jump(<s:property value="pager.currentPage-1"/>,<s:property value="pager.pageSize"/>)">上一页</a>
</s:else>
<s:if test="pager.currentPage == pager.pageCount">
下一页
末页
</s:if>
<s:else>
<a href="javascript:jump(<s:property value="pager.currentPage+1"/>,<s:property value="pager.pageSize"/>)">下一页</a>
<a href="javascript:jump(<s:property value="
pager.pageCount"/>,<s:property value="pager.pageSize"/>)">末页</a>
</s:else>
转到<s:textfield name="pager.currentPage" id="gPage" cssStyle="width:20px;"></s:textfield>
<input type="button" value="GO" onclick="jump(document.getElementById('gPage').value,<s:property value="pager.pageSize"/>)" />
每页显示:<s:select list="#{3:'3',5:'5',10:'10',20:'20' }" name="pager.pageSize" onchange="jump(1,this.value)"></s:select>
</td>
</tr>
</table>
/**
* 分页显示数据信息
*/
public Pager<User> getUsersByPage(int currentPage, int pageSize,
User condition) throws DAOException {
String hql = "from User where 1=1";
Map<String, Object> params = new HashMap<String, Object>();
if(condition != null){
if(condition.getUsername() != null && !"".equals(
condition.getUsername().trim())){
hql += " and username like :username";
params.put("username", "%"
+condition.getUsername().trim()+"%");
}
if(condition.getPassword() != null && !"".equals(
condition.getPassword().trim())){
hql += " and password =:password";
params.put("password", condition.getPassword().trim());
}
if(condition.getStatus() != null && condition.getStatus() != 0){
hql += " and status =:status";
params.put("status", condition.getStatus());
}
}
return super.findPager(hql, currentPage, pageSize, params);
}
public String findUsers(){
try {
//userList = userService.findAllUsers();
if(pager == null){
pager = new Pager<User>();
}
pager = userService.getUsersByPage(
pager.getCurrentPage(),pager.getPageSize(), item);
return SUCCESS;
} catch (Exception e) {
log.error("method findUsers bug :{}",e);
return ERROR;
}
}
<action name="findUsers" class="userAction" method="findUsers">
<result>/WEB-INF/pages/userList.jsp</result>
</action>
权限:认证--授权(权限菜单的展示--权限的控制--权限的分配)
多表和基于角色的权限管理:用户--角色--权限(菜单)
tb_user--tb_role|tb_role_right(关联表)|tb_right(菜单)
实体类和映射文件反转生成:右键MyEclipse>添加Hibernate支持
DB Brower>右键表>HibernateReverse>CreateHibernateMappingFile(*.hbm.xml)
tb_user:id(pk) username password status createtime role_id(fk)
tb_role:id(pk) rolename
tb_right:right_code(pk-String|1001>100101) right_title right_url
right_parent_code(ROOT_MENU|1001)
tb_role_right:id(pk) role_id(fk) right_code(fk)
TbUser:
private TbRole tbRole;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id")
public TbRole getTbRole() {
return this.tbRole;
}
public void setTbRole(TbRole tbRole) {
this.tbRole = tbRole;
}
<td>角色</td>
<td>
<-- ManyToOne关联 -->
<s:property value="tbRole.rolename" />
</td>
web.xml:
<!-- 使用Hibernate延迟加载,不会因Session被关闭,导致延迟加载数据异常,等到返回响应后才关闭session -->
<!-- 一定要在struts2过滤器之前 -->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
RoleRightImpl:
public List<TbRight> getRightsByRoleId(int roleId) throws DAOException{
String hql = "select rr.tbRight from TbRoleRight rr where
rr.tbRole.id=:roleid";
Map<String, Object> params = new HashMap<String, Object>();
params.put("roleid", roleId);
return super.queryListByHql(hql, params);
}
UserAction:
putToSession("loginUser",item);
putToSession("loginRoleId", item.getTbRole().getId());//存入session
RoleAction:
private List<TbRight> rightList;
public String findCurrentRights(){
try {
rightList = roleRightService.getRightsByRoleId(
(Integer)getFromSession("loginRoleId"));//获取session中数据
resultMap.put("retcode", RetCode.SUCCESS);//存入resultMap
resultMap.put("rightList", rightList);//避免死循环->排除
} catch (Exception e) {
log.error("method login bug:"+e);
resultMap.put("retcode", RetCode.UNKOWN_WRONG);
resultMap.put("retmsg", "未知错误!请重试或联系管理员!");
}
return SUCCESS;
}
<!-- 排除rightList<TbRole>中的tbRoleRights -->
<action name="findCurrentRights" class="roleAction" method=
"findCurrentRights">
<result type="json">
<param name="root">resultMap</param>
<param name="excludeProperties">
rightList\[\d+\]\.tbRoleRights
</param>
</result>
</action>
权限菜单展示:dTree目录树
tree.add(id,pid,name,url,title,target,icon,iconOpen,open);
id :节点自身的id
pid :节点的父节点的id
name :节点显示在页面上的名称
url :节点的链接地址
title :鼠标放在节点上所出现的提示信息
target :节点链接所打开的目标frame(如框架目标mainFrame或_blank,_self之类)
icon :节点关闭时的显示图片的路径
iconOpen :节点打开时的显示图片的路径
open :布尔型,节点是否打开(默认为false)
注:open项:顶级节点一般采用true,即pid是-1的节点
1:默认值的书写规则(从左至右,依次省略)
即 tree.add(id,pid,name,url);后面5个参数可以省略
2:有间隔时的默认值(如存在第6个参数,但第5个参数想用默认值)即 tree.add(id,pid,name,url,"",target);必须这样写
其它:tree.add(id,pid,name,url,"","","","",true);
dtree.js:
// Tree object
function dTree(objName) {
this.config = {target:null, folderLinks:true, useSelection:true, useCookies:true, useLines:true, useIcons:true, useStatusText:false, closeSameLevel:false, inOrder:false};
this.icon = {root:"dtree_/img/doc.gif", folder:"dtree_/img/doc.gif", folderOpen:"dtree_/img/doc.gif", node:"dtree_/img/doc.gif", empty:"dtree_/img/empty.gif", line:"dtree_/images/menu/win/line.gif", join:"dtree_/images/menu/win/join.gif", joinBottom:"dtree_/images/menu/win/joinbottom.gif", plus:"dtree_/images/menu/win/plus.gif", plusBottom:"dtree_/images/menu/win/plusbottom.gif", minus:"dtree_/images/menu/win/minus.gif", minusBottom:"dtree_/images/menu/win/minusbottom.gif", nlPlus:"dtree_/images/menu/win/nolines_plus.gif", nlMinus:"dtree_/images/menu/win/nolines_minus.gif"};
this.obj = objName;
this.aNodes = [];
this.aIndent = [];
this.root = new Node(-1);
this.selectedNode = null;
this.selectedFound = false;
this.completed = false;
}
<link rel="stylesheet" type="text/css" href="${ctx}/dtree_/dtree.css"/>
<script type="text/javascript" src="${ctx}/dtree_/dtree.js"></script>
<script type="text/javascript">
var d = new dTree("d");//全局初始化
$(function(){
//发送ajax请求菜单
var url = "${ctx}/user/findCurrentRights.action";
$.post(
url,
{},
function(data){
if(data.retcode =="0"){
d.add("ROOT_MENU","-1","OA管理系统");
//each方法遍历(value=rightList中每一项)
$.each(data.rightList,function(i,value){ d.add(value.rightCode,value.rightParentCode
,value.rightTitle,value.rightUrl
,'','rightFrame','','','',0);
});
$("#menuDiv").html(d.toString());
}
}
);
});
</script>
<body style="background-color:#0066CC;">
<div id="menuDiv"></div>
</body>
tb_right表:right_url=user/findUsers.action(可以加一张表CRUD维护url)
权限框架(Shiro|Spring Security):权限控制-权限分配
Apache Shiro:认证Authentication、授权Authorization、加密、会话管理、缓存
ApplicationCode-->Subject(主体)->SecurityManager(安全管理器)->Realm(域)
Shiro不会去维护用户、维护权限;需要去设计/提供;通过Realm注入给Shiro即可。
全注解:
DB Brower>右键表>HibernateReverse>AddHibernateMappingAnnotationsJOPO
实体类TbUser:
@Entity
@Table(name = "tb_user")
public class TbUser implements java.io.Serializable
@Id
@GeneratedValue
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id")
public TbRole getTbRole() {
return this.tbRole;
}
@Column(name = "username", length = 20)
public String getUsername() {
return this.username;
}
dao层:@Repository("userDao")
service层:@Service("userService")
BaseService/BaseService注入:
@Autowired
protected UserDao userDao;
@Autowired
protected UserService userService;
action层:
//spring注解
@Controller("userAction")
@Scope("prototype")
//struts2注解
@Namespace("/user")
@ParentPackage("struts-base")
//struts-admin注解
@Action(value = "ajaxLogin",results = {@Result(name = "success", type="json",params={"root","resultMap"}) })
public String ajaxLogin()
@Action(value = "findUsers",results = {@Result(name = "success" ,location="/WEB-INF/pages/userList.jsp") })
public String findUsers()
@Controller("roleAction")
@Scope("prototype")
@Namespace("/user")//jar包:struts-convention-plugin-2.3.4.1
@ParentPackage("struts-base")
public class RoleAction extends BaseAction
@Action(value = "findCurrentRights",results = {@Result(name = "success",type="json",params={"root","resultMap","excludeProperties","rightList\\[\\d+\\]\\.tbRoleRights"}) })
public String findCurrentRights()
aplicationContext.xml:
<!-- 自动根据名字找注解 -->
<beans xsi: default-autowire="byName">
<!-- 注解扫描 -->
<context:component-scan base-package="com.hfxt.*" />
<!-- sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="annotatedClasses">
<list>
<value>com.hfxt.entity.TbUser</value>
<value>com.hfxt.entity.TbRole</value>
<value>com.hfxt.entity.TbRight</value>
<value>com.hfxt.entity.TbRoleRight</value>
</list>
</property>
MyBatis
MyBatis(ibatis):持久化层框架;把sql写到专门的配置文件
- lib下添加jar包:mybatis-3.1.1.jar
- src下添加配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 别名alias -->
<typeAliases>
<typeAlias alias="user" type="com.hfxt.entity.User"/>
<typeAlias alias="role" type="com.hfxt.entity.Role"/>
</typeAliases>
<!-- 开发环境 -->
<environments default="development">
<environment id="development">
<!-- 配置数据库连接信息 -->
<transactionManager type="JDBC"/>
<!--事务管理类型主要有jdbc和managed,前者依赖于数据源获得的连接,后者依赖于容器 -->
<!-- POOLED数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value=
"jdbc:mysql://localhost:3306/t38?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!-- 引入实体类mapper -->
<mappers>
<mapper resource="com/hfxt/mapper/UserMapper.xml" />
<mapper resource="com/hfxt/mapper/RoleMapper.xml" />
</mappers>
</configuration>
- 创建实体类及SQL映射文件(CRUD):sql语句--方法映射文件
com.hfxt.mapper.UserMapper.xml-RoleMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- UserDao接口的完全限定名 命名空间唯一 -->
<mapper namespace="com.hfxt.dao.UserDao">
<!-- 映射sql语句 id与UserDao接口中方法名相同可省略实现类 -->
<select id="getAllCount" resultType="int">
select count(*) from tb_user
</select>
<!-- <select id="getAllUsers" resultType="user">
select
id as id,
username as username,
password password,
status as status,
createtime as createtime,
role_id roleId
from tb_user
</select> -->
<!-- <select id="getAllUsers" resultMap="rm_users">
select * from tb_user
</select> -->
<!-- 多表:内联查询 -->
<select id="getAllUsers" resultMap="rm_users">
select a.*,b.rolename from tb_user a
inner join tb_role b
on a.role_id=b.id
</select>
<!-- 模糊查询
<select id="getUsers" resultMap="rm_users" parameterType="user">
select * from tb_user where 1=1
<if test="username != null">
and username like '%${username}%'
</if>
<if test="password != null">
and password = #{password}
</if>
<if test="status != null">
and status = #{status}
</if>
<if test="roleId != null">
and role_id = #{roleId}
</if>
</select> -->
<!-- 模糊查询常用写法 -->
<select id="getUsers" resultMap="rm_users" parameterType="user">
select * from tb_user
<where>
<if test="username != null">
and username like '%${username}%'
</if>
<if test="password != null">
and password = #{password}
</if>
<if test="status != null">
and status = #{status}
</if>
<if test="roleId != null">
and role_id = #{roleId}
</if>
</where>
</select>
<insert id="addUser" parameterType="user">
<!-- oracle序列
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select seq_user.nextval from dual
</selectKey> -->
insert into tb_user(username,password,status,createtime,role_id)
values(#{username},#{password},#{status},now(),#{roleId})
</insert>
<update id="updateUser" parameterType="user">
update tb_user
<set>
<if test="username != null">
username=#{username},
</if>
<if test="password != null">
password=#{password},
</if>
<if test="status != null">
status=#{status},
</if>
<if test="roleId != null">
role_id=#{roleId},
</if>
</set>
where id=#{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from tb_user where id=#{id}
</delete>
<!-- 字段名与属性名映射-->
<resultMap type="user" id="rm_users">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="status" property="status" />
<result column="createtime" property="createtime" />
<result column="role_id" property="roleId" />
<!-- 多对一(不常用)
<collection property="role" column="role_id" select="com.hfxt.dao.RoleDao.getRoleById"></collection> -->
<result column="rolename" property="rolename" />
</resultMap>
</mapper>
<mapper namespace="com.hfxt.dao.RoleDao">
<select id="getRoleById" resultMap="rm_roles" parameterType="int">
select * from tb_role where id=#{id}
</select>
<resultMap type="role" id="rm_roles">
<id column="id" property="id" />
<result column="rolename" property="rolename" />
</resultMap>
</mapper>
- 编写实体类及测试类:UserDao(User)--RoleDao(Role):
private Integer id;
private String username;
private String password;
private Integer status;
private Date createtime;
private Integer roleId;
private String rolename;//业务字段
//private Role role;//多对一
public interface UserDao {
public int getAllCount();
public List<User> getAllUsers();
public List<User> getUsers(User condition);
public int addUser(User item);
public int updateUser(User item);
public int deleteUser(int id);
}
private Integer id;
private String rolename;
public interface RoleDao {
public Role getRoleById(int id);
}
- 测试类Test--MD5Util:MD5加密解密
public class MD5Util {
/***
* MD5加码 生成32位md5码
*/
public static String string2MD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
/**
* 加密解密算法 执行一次加密,两次解密
*/
public static String convertMD5(String inStr) {
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ 't');
}
String s = new String(a);
return s;
}
// 测试主函数
public static void main(String args[]) {
String s = new String("aaa");
System.out.println("原始:" + s);
System.out.println("MD5后:" + string2MD5(s));
System.out.println("加密的:" + convertMD5(s));
System.out.println("解密的:" + convertMD5(convertMD5(s)));
}
}
public static void main(String[] args) {
SqlSession session = null;
try {
Reader reader = Resources.getResourceAsReader(
"mybatis-config.xml");
SqlSessionFactoryBuilder builder = new
SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = builder.build(reader);
session = sessionFactory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
/*int count = userDao.getAllCount();
System.out.println(count);*/
/*List<User> list = userDao.getAllUsers();
for(User user : list){
System.out.println(user.getUsername()+user.getRoleId()); }*/
/*增加
User item = new User();
item.setUsername("sb");
item.setPassword(MD5Util.string2MD5("123"));//MD5加密
item.setStatus(1);
item.setRoleId(1);
int count = userDao.addUser(item);
session.commit();
System.out.println(count);*/
/*修改
User item = new User();
item.setId(12);
item.setPassword(MD5Util.string2MD5("abc"));
session.commit();
int count = userDao.updateUser(item);
System.out.println(count);*/
/*删除
int count = userDao.deleteUser(13);
session.commit();
System.out.println(count);*/
/*模糊查询条件
User condition = new User();
condition.setUsername("a");
condition.setPassword("123");
List<User> list = userDao.getUsers(condition);
for(User user : list){
System.out.println(user.getUsername()+"||"+user.getRoleId());
}*/
//多表连接
List<User> list = userDao.getAllUsers();
for(User user : list){
//System.out.println(user.getUsername()+"||"
+user.getRole().getRolename());
System.out.println(user.getId()+"||"+user.getUsername()
+"||"+user.getRolename() );
}
} catch (IOException e) {
e.printStackTrace();
} finally{
session.close();
}
}
springMVC
spring MVC:SpringFrameWork后续产品+实现Web MVC设计模式的请求驱动类型的轻量级Web框架;分离了控制器、模型对象、分派器以及处理程序对象的角色
实现步骤:http://localhost:8080/ssm1/hello->核心控制器(拦截所有请求)>加载
springmvc.xml->HelloController(/Hello)>return "hello"->/WEB-
INF/page/hello.jsp
Spring MVC配置步骤:
- 添加jar包(同spring):mvc、aop、core相关包
- web.xml中添加核心控制器
<!-- springmvc -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 不在WEB-INF目录下或以springServlet命名,需添加的参数 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<!-- 服务器启动就初始化 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<!-- 拦截所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
- 配置文件spring-mvc.xml
<!--
1。配置action,实现controler接口
2。配置映射处理器,用来处理请求与action的映射,可以不用写id,
3。配置视图解析器:完成ModelAndView的解析
-->
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- 扫描(注解的Controller) -->
<context:component-scan base-package="com.hfxt.web.controller" />
<!-- 视图解析 -->
<bean id="viewResolver"class="org.springframework.web.servlet
.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/page/" p:suffix=".jsp" />
</beans>
- com.hfxt.web.controller
HelloController:
@Controller
public class HelloController {
/*@RequestMapping("/hello")
public String sayHello(ModelMap map){
map.put("message", "这是我的第一个springmvc的项目");
return "hello";
}*/
@RequestMapping("/hello")
public ModelAndView sayHello(){
ModelAndView mv = new ModelAndView();
mv.addObject("message", "这是我的第一个springmvc的项目");
mv.setViewName("hello");
return mv;
}
}
UserController:
@Controller
public class UserController {
@RequestMapping(value="/login",method=RequestMethod.GET)
public String toLogin(){
return "login";
}
@RequestMapping(value="/login",method=RequestMethod.POST)
//接收请求参数:名字一样自动填充
//public String doLogin(@RequestParam("username") String
username,@RequestParam("password") String password){
//public String doLogin(String username,String password){
public String doLogin(String username,String password
,HttpSession session){
if("admin".equals(username) && "123".equals(password)){
//session存值
session.setAttribute("loginUser", username);
return "success";
}else{
return "login";
}
}
}
- WEB-INF/page/hello.jsp|login.jsp|success.jsp:
<body>
${message }
</body>
<form action="login" method="post">
用户名:<input type="text" name="username" /><br />
密码:<input type="password" name="password" /><br />
<input type="submit" value="登陆" />
</form>
<body>
登陆成功!欢迎您${sessionScope.loginUser }
</body>
SSM
SSM框架整合:MyBatis+Spring+SpringMVC
Spring+myBatis整合:新建项目并导入jar包>配置mybatis-config.xml>创建库及表>创建实体>编写映射文件,修改mybatis-config.xml内容>进行简单测试
整合springmvc: 添加spring-mvc.xml>修改web.xml文件,加入springmvc相关信息>编写控制器类及相关jsp文件
- com.hfxt.mapper. UserMapper.xml>UserDao>UserSerive>UserServiceImpl
<select id="getUserByUsername" parameterType="String"
resultMap="rm_users">
select * from tb_user where username=#{username}
</select>
public User getUserByUsername(String username);
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User checkLogin(String username, String password) {
User user = userDao.getUserByUsername(username);
if(user != null && user.getPassword().equals(password)){
return user;
}
return null;
}
}
- applicationContext.xml(类中采用注解注入对象):
<!-- 扫描dao/service层 -->
<context:component-scan base-package="com.hfxt.service,com.hfxt.dao" />
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 数据源c3p0 -->
<bean id="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
<property name="minPoolSize" value="${jdbc.minPoolSize}" />
<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
</bean>
<!-- sessionFactory 将spring和mybatis整合
<description>
Spring与Mybatis相关的配置文件
typeAliasesPackage:可以配置多个,用','号分隔
basePackage:可以配置多个,用','号分隔
</description> -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.
SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 加载Mapper -->
<property name="mapperLocations">
<list>
<value>classpath*:com/hfxt/mapper/*Mapper.xml</value>
</list>
</property>
<!-- 实体类前缀(实体域domain,这里是entity) -->
<property name="typeAliasesPackage" value="com.hfxt.entity" />
</bean>
<!-- Mybatis和spring整合 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hfxt.dao" />
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory" />
</bean>
- com.hfxt.web.controller. UserController>spring_mvc.xml:
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value="/login",method=RequestMethod.GET)
public String toLogin(){
return "login";
}
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(User item,HttpSession session){
User user = userService.checkLogin(item.getUsername()
,item.getPassword());
if(user != null){
session.setAttribute("loginUser", user);
return "success";
}else{
return "login";
}
}
//ajax请求
@ResponseBody
//取得?id=1的值
public Map<String, Object> doAjaxLogin(@PathVariable("id") int
id,User item,HttpSession session){
Map<String, Object> modelMap = new HashMap<String, Object>();
item = userService.checkLogin(item.getUsername()
,item.getPassword());
if(item != null){
session.setAttribute("loginUser", item);
modelMap.put("retcode", "0");//返回json数据
}else{
modelMap.put("retcode", "101");
}
return modelMap;
}
}
<!-- 扫描 -->
<context:component-scan base-package="com.hfxt.web.controller" />
<!-- 视图解析 -->
<bean id="viewResolver" class="org.springframework.web.servlet
.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/page/" p:suffix=".jsp" />
- web.xml:
<!-- spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*Context.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 中文过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- springmvc -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- WEB-INF/page/login.jsp|success.jsp:
<form action="login" method="post">
<!-- springmvc:属性与name相同自动填充 -->
用户名:<input type="text" name="username" /><br />
密码:<input type="password" name="password" /><br />
<input type="submit" value="登陆" />
</form>
<body>
登陆成功!欢迎您${sessionScope.loginUser.username }
</body>
项目开发
项目生命周期:需求分析(功能)>项目设计(数据库设计|系统架构设计)>代码(编码规范)>测试>实施部署(部署|试运行|运行)>验收(初验|中验|终验)
数据库设计:设计库、表、表关系
系统架构设计:开发(CRUD基本业务-公用类-公用组件-平台开发-面向解决方案开发)
项目结构(分层、应用组件及版本、工具类)
开发规范与约定:软件框架版本-开发环境-包约定-页面约定-数据库规范-分层约定
框架(SSH/SSM)-软件技术(Junit/JQuery/EasyUI/SVN/Maven)
开发环境:OS-JDK-IDE(MyEclipse)-数据库(MySQL)-Web容器(Tomcat)
页面约定:JSP/CSS/JS、前端JSTL标签、权限页面放在WEB-INF下
数据库约定:编码UTF-8、不要设置自定义/非空/外键约束、sql语句完整
分层约定:控制层调Service,Service调Dao、层与层之间用接口、数据传输对象
web层>控制层>业务层>Dao层
SSH:dao/dao.impl-service/service.impl-action-model-util-interceptor-listener-filter
SSM:dao/dao.impl-service/service.impl-controller-entity-util-listener -interceptor
代码生成工具:codesmith、Mybatis Genertor
设置:Tools->Options...->Studio->Editor->Enable unicode->显示中文
模板说明区域-属性设置区域-注册模板区域-引用声明区域-模板区域-函数区域
- 创建一个命令行应用solution
- CodeSmith的Schema Explorer>添加一个MySQL数据源(Connection String: SERVER=localhost;DATABASE=sales;UID=username;PASSWORD=password;)
- 当前solution添加一个Sales Data Class Library,然后在项目中添加一个CodeSmith 项目Item
- 分别添加三个模板,SourceDatabase 选择Schema Explorer 中添加的Sales数据库,其它属性使用缺省值>Sales.csp的Generate.code生成代码
Hbms(生成hbm.xml映射文件)、Entities(生成和数据库表对应的.Net类定义)、Queries(生成查询数据对应的类)
svn版本控制工具: git工具(开源的分布式版本控制系统)
组长--搭好框架--> svn服务器-->组员(检出checkout-更新update-提交commit)
- 安装MyEclipse插件:MyEclipse安装位置->拷贝svn.link
(path=D:\\Java\\myplugins\\svn)->SVN资源库->新建资源库位置(项目url)
trunk目录-->导入项目(递归子目录)--检出为->Team更新->提交(去除/classes)
- 客户端工具:安装TortoiseSVN->右键SVNCheckout--设置项目url/trunk和项目目录->导入MyEclipse->SVNUpdate-SVNCommit(默认不勾选/classes目录)
右键TortoiseSVN>Showlog(查看历史纪录)-Show Conflict(代码冲突)
Maven:项目构建工具和管理jar包
Maven安装配置:eclipse必须添加一个支持maven插件m2eclipse
- 解压缩->配置环境变量
新建系统变量MAVEN_HOME 变量值:D:\Java\apache-maven-3.3.9
编辑系统变量Path 添加变量值:;%MAVEN_HOME%\bin
测试:mvn -v
- maven目录下config>settings.xml(配置jar包下载路径:<localRepository>
D:\Java\apache-maven-3.3.9\repos</localRepository>)
- MyEclipse配置插件->preferences>Maven4MyEclipse配置settings.xml和maven目录
- 新建MavenProject>选择模板(*-webapp)>GroupId|项目名|version
源文件夹:main/resources main/java test/resources test/java main/webapp
配置文件pom.xml:镜像nexus(代理下载包)
<!-- 从maven repository(jar包仓库)下载 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
- 运行项目:jetty插件
MyEclipse安装位置>jetty放在dropins目录下>Run配置JettyWebApp>改Context:/t38
<build>
<finalName>t38</finalName>
<plugins>
<!-- jetty插件 -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.5</version>
<configuration>
<webAppSourceDirectory>
src/main/webapp
</webAppSourceDirectory>
<scanIntervalSeconds>3</scanIntervalSeconds>
<contextPath>/t38</contextPath>
<connectors>
<connector implementation="
org.mortbay.jetty.nio.SelectChannelConnector">
<port>8080</port>
</connector>
</connectors>
</configuration>
</plugin>
</plugins>
</build>
WebService
WebService:一个部署在Web服务器上的一个应用程序,它向外界暴露出一个能够通过Web进行调用的API
Soap(XML)+WSDL+HTTP
客户端(调用Web Service的应用程序)-服务器(发布web Service服务)
跨平台调用-跨语言调用-可远程调用
webservice 调用方式(3种):httpget-httppost-httpsoap
CXF开发Web Service服务端:
1.新建 项目(这里用scm 环境)
2.导入cxf相关jar包
asm-3.3.jar
aopalliance-1.0.jar
jett*-1.3.jar(jett开头的多个jar)
spring*.RELEASE(spring开头的多个jar)
3.修改web.xml文件
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
4.新建服务类:添加@WebService注解,代表发布一个WebService服务;类中所有的静态、final、非公有的方法都将不会对外公布@WebMethod(exclude=true),阻止对外公开
@WebService
@Component("accountReportWs")
public class AccountReportWs {
@Resource
private AccountRecordsService accountRecordsService;
//传json数据,再自己组装成map对象
public String selectSupplier(String json){
System.out.println("json:"+json);
ObjectMapper mapper = new ObjectMapper();
try {
Map<String,String> map = mapper.readValue(json, HashMap.class);
List<Map<String, Object>> selectSupplier = accountRecordsService.selectSupplier(map);
//结果组装成json字符串
String returnJson = mapper.writeValueAsString(selectSupplier);
System.out.println("returnjson:"+returnJson);
return returnJson;
} catch (Exception e) {
e.printStackTrace();
return "exception:"+e.getMessage();
}
//return "nothing";
};
}
5. 配置applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation=
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!--采用注解,不采用配置 <bean id="accountRecordsWebService" class="cn.xxx.service.impl.AccountRecordsServiceImpl" /> -->
<!-- id:逻辑名 serviceClass=服务接口类 address:调用的路径,如下可以使用 http://localhost:8080/项目名/ws/hello?wsdl>,其中ws资源路径在web.xml中servlet中配置 -->
<jaxws:server id="arws" serviceClass="cn.itcast.ws.AccountReportWs" address="/hello">
<jaxws:serviceBean>
<!--采用注解的相关bean -->
<ref bean="accountReportWs" />
</jaxws:serviceBean>
</jaxws:server>
6.启动服务器,发布web服务
CXF开发Web Service客户端:
1.新建项目
2.使用wsimport生成客户端代码
wsimport -s . -p cn.xxx.demo5 xxx.sss.xxx?WSDl
3.把代码存放到项目中
4.添加接口
public interface WsClient {
public String selectSupplier(String json) ;
}
5.添加客户端调用实现类
@Component("wsClient")
public class WsClientImpl implements WsClient {
private AccountReportWs getAccountReportWs(){
AccountReportWsService accountReportWsService = new AccountReportWsService();
return accountReportWsService.getAccountReportWsPort();
}
public String selectSupplier(String json) {
System.out.println("clientimpl.json:"+json);
//WsClientImpl wsClientImpl = new WsClientImpl();
//String json = "{\"start\":\"2010-10-10\",\"end\":\"2016-09-09\"}";
String returnJson = getAccountReportWs().selectSupplier(json);
return returnJson;
}
}
6.修改控制类
@Controller
@RequestMapping(value="/accountRecords")
public class AccountRecordsAction extends BaseAction {
@Resource
private AccountRecordsService accountRecordsService;
@Resource
private WsClient wsClient;
@RequestMapping(value="/selectSupplier")
@ResponseBody
public Object selectSupplier(String start,String end){
System.out.println("start:"+ start+"||end:"+end);
//组装json数据
String json = "{\"start\":\""+start+"\",\"end\":\""+end+"\"}";
String returnJson= wsClient.selectSupplier(json);
return returnJson;
}
}