SSH综合练习-仓库管理系统-第一天 javascript
综合练习的总体目的:css
整合应用 Struts2 、Hibernate、Spring 、Mysql 、 jQuery Ajax、java基础知识html
今天的主要内容: java
原型就是软件的一个早期可运行的版本,它实现了目标系统的某些功能,主要用于和用户肯定其明确的需求。以及开发编码的基础页面。mysql
原型:低精度+高精度jquery
咱们这里提供的原型就是仓库管理系统静态页面的工程。web
【思考】ajax
如何导入原型工程?spring
新建Web项目storemanager:sql
导入静态页面和源码配置等:
页面赋值到WebRoot,源码和配置复制到src
【提示】
复制的时候,不要覆盖WEB-INF和META-INF目录。
【部署测试】
将工程部署到tomcat中,启动服务器,查看是否正常能访问。
详细功能能够参考需求文档,也能够查看原型来了解。
要开发的功能以下:
数据表:
表之间的关系:
表之间的关系:
用户表:userinfo表,独立
表名(英文) |
||||||
用户表 |
userinfo |
|||||
序号 |
字段名 |
类型 |
长度 |
NULL |
说明 |
|
1 |
id |
varchar |
32 |
no |
主键ID |
|
2 |
name |
varchar |
50 |
yes |
用户名 |
|
3 |
password |
varchar |
32 |
yes |
密码 |
仓库表:store
1----- * 货物goods (一个仓库 能够存放多种货物 )
表名(英文) |
||||||
仓库表 |
store |
|||||
序号 |
字段名 |
类型 |
长度 |
NULL |
说明 |
|
1 |
id |
varchar |
32 |
no |
主键ID |
|
2 |
name |
varchar |
32 |
yes |
仓库名称 |
|
3 |
addr |
varchar |
100 |
yes |
仓库地址 |
|
4 |
Manager |
varchar |
32 |
yes |
仓库管理员 |
货物表:goods
1 ---- * 历史记录history (一种货物,可能出入库屡次,每次操做都要记录历史 )
表名(英文) |
||||||
货物表 |
goods |
|||||
序号 |
字段名 |
类型 |
长度 |
NULL |
说明 |
|
1 |
id |
varchar |
32 |
no |
主键ID |
|
2 |
name |
varchar |
50 |
yes |
货物名称 |
|
3 |
nm |
varchar |
10 |
yes |
简记码 |
|
4 |
unit |
varchar |
10 |
yes |
计量单位 |
|
5 |
amount |
double |
yes |
出/入库数量 |
||
6 |
storeid |
varchar |
32 |
yes |
仓库id,对应仓库表主键 |
历史记录表:history
表名(中文) |
表名(英文) |
|||||
历史记录表 |
history |
|||||
序号 |
字段名 |
类型 |
长度 |
NULL |
说明 |
|
1 |
id |
varchar |
32 |
no |
主键ID |
|
2 |
goodsid |
varchar |
32 |
yes |
货物id,对应货物表主键 |
|
2 |
datetime |
varchar |
19 |
yes |
操做时间(当前时间) |
|
3 |
_type |
varchar |
1 |
yes |
出/入库标识,1入库,2出库 |
|
4 |
amount |
double |
yes |
本次出/入库数量 |
||
5 |
remain |
yes |
余量 |
|||
6 |
_user |
varchar |
50 |
yes |
操做人(Session中获取),直接保存名称,不引用userinfo表 |
Mysql:
使用一个用户,建一个数据库,将脚本在该数据库上运行,创建相应的表。
步骤:
在Add User页面中,用户名和密码都是store
登陆以后:
create table userinfo( /*用户表*/
id varchar(32) primary key,
name varchar(50),/*登陆名*/
password varchar(32)/*密码*/
);
/*仓库表*/
create table store(
id varchar(32) primary key,
name varchar(32),/*仓库名称*/
addr varchar(100),/*仓库所在地*/
manager varchar(32) /*仓库管理人员,不关联userinfo表*/
);
/*货物表*/
create table goods(
id varchar(32) primary key,
name varchar(50),/*货物名称*/
nm varchar(10),/*货物简记内码,如阿斯匹林为ASPL*/
unit varchar(10), /*计量单位,1:个,2:GK,3:只,..*/
amount numeric(10,2),/*库存数量*/
storeid varchar(32),/*所在仓库ID*/
constraint foreign key(storeid) references store(id)
);
/*出入库历史记录*/
create table history(
id varchar(32) primary key,
goodsid varchar(32),/*货物ID*/
datetime varchar(19),/*出入库时间*/
_type char(1),/*类型1:入库,2:出库*/
amount numeric(10,2),/*此次出入库的数量*/
remain numeric(10,2),/*余量*/
_user varchar(50), /*操做员名称,直接保存名称,不引用userinfo表*/
constraint foreign key(goodsid) references goods(id)
);
技术选型:要用什么技术组件(ssh+mysql)
方式:引入ssh的jar和相关配置(web.xml和一些核心配置文件)
参考:须要的材料:课前资料中的
第一步:导入jar包。
第二步:导入web.xml(struts的过滤器和spring的监听器):
能够直接覆盖WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<!-- Spring ServletContextListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 加载配置文件默认 WEB-INF/applicationContext.xml -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
第三步:导入配置文件:
一般实际项目开发时 : "项目源码、测试代码、配置文件" 通常是分开的,因此咱们首先来规划一下源码文件夹。
新建源码文件夹:
命名为resource(用来存放资源文件)
命名为test(用来存放测试文件)
咱们能够新建不一样功能的源代码文件夹:
将配置文件都复制到resources。
最终结果:
其中:
jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql:///itcaststore
jdbc.username = store
jdbc.password = store
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout
国际化资源文件:用来实现项目的国际化
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--
开发者模式:关闭:反作用:若是是ajax请求的状况下,一旦出错,不会在页面上打印错误
因此采用struts.i18n.reload和struts.configuration.xml.reload的模式
-->
<!-- <constant name="struts.devMode" value="true" /> -->
<!-- 不用重启服务器 -->
<constant name="struts.i18n.reload" value="true" />
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 表单样式 -->
<constant name="struts.ui.theme" value="simple" />
<!-- 加载src下的国际化文件messages.properties -->
<constant name="struts.custom.i18n.resources" value="messages" />
<package name="default" namespace="/" extends="struts-default">
</package>
</struts>
(5)applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 链接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- sessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 第一部分: 链接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 第二部分: hibernate经常使用属性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 第三部分: 引入hbm -->
<!-- <property name="mappingResources">
<list>
<value>cn/itcast/storemanager/domain/Goods.hbm.xml</value>
<value>cn/itcast/storemanager/domain/History.hbm.xml</value>
<value>cn/itcast/storemanager/domain/Store.hbm.xml</value>
<value>cn/itcast/storemanager/domain/Userinfo.hbm.xml</value>
</list>
</property> -->
<!-- 能够批量引入hbm
支持通配符
-->
<property name="mappingLocations">
<list>
<value>classpath:cn/itcast/storemanager/domain/*.hbm.xml</value>
</list>
</property>
</bean>
<!-- 配置事务 -->
<!-- 配置事务管理器平台 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 事务管理通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" read-only="false"/>
<tx:method name="update*" read-only="false"/>
<tx:method name="delete*" read-only="false"/>
<tx:method name="find*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 切入点和切面 -->
<aop:config>
<aop:pointcut expression="bean(*Service)" id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
不建议在原来项目上生成 ,新建web 项目abcdefg,用来保存生成的po类和hbm。
点击:
切换Database Explorer 视图,
新建数据库链接
选择Myeclipse视图,选择abcdefg项目,对abcdefg项目添加hibernate支持
选择Hibernate的版本
点击下一步:选择DB Driver
选择abcdefg项目,建立包cn.itcast.storemanager.domain用来存放持久化对象和配置文件。
回到数据透视图,选择表,进行反转生成
配置选项
注意:两点:
修改applicationContext.xml 引入hbm映射
<!-- 第三部分: 引入hbm -->
<property name="mappingResources">
<list>
<value>cn/itcast/storemanager/domain/Goods.hbm.xml</value>
<value>cn/itcast/storemanager/domain/History.hbm.xml</value>
<value>cn/itcast/storemanager/domain/Store.hbm.xml</value>
<value>cn/itcast/storemanager/domain/Userinfo.hbm.xml</value>
</list>
</property>
最后:测试实体类是否正常:
删除数据库表,重启服务,看是否报错和自动生成表。
【扩展知识】批量映射配置:
<!-- 能够批量引入hbm
支持通配符
-->
<property name="mappingLocations">
<list>
<value>classpath:cn/itcast/storemanager/domain/*.hbm.xml</value>
</list>
</property>
【业务逻辑梳理】
用户在页面输入用户和密码 -----> 数据封装model --->- 经过Service传递到Dao 查询数据库 ---> 返回Userinfo对象 ---->
若是正确,将登陆信息保存到session,
若是不正确,封装ActionError 返回登陆页面。
创建相应的包:
目标页面:login.jsp
使用struts2 标签,由于须要回显功能,新增struts标签的taglib:
<%@ taglib uri="/struts-tags" prefix="s" %>
修改原来的form:
<s:form name="loginForm" action="user_login" namespace="/" method="post" cssStyle="margin-top:250px;">
</s:form>
注意:struts2标签使用的标准的html标签,所以,属性必须加双引号。
修改其余标签:
用户名:<s:textfield name="name" cssClass="tx" maxLength="15" size="15" />
密码:<s:password name="password" cssClass="tx" maxLength="15" size="15"/>
增长验证信息显示标签:
<TR>
<TD align="center" colSpan=3 width="623" height="260"
background="<c:url value='/picture/welcome_01.gif'/>">
<!-- 验证码返回提示 --> <br> <br> <br> <br> <br>
<font color="#ff60a0" size="5">
<!-- 回显错误表单信息:表单校验错误,针对具体字段 -->
<s:fielderror></s:fielderror>
<!-- 回显通常错误信息 -->
<s:actionerror/>
</font>
</TD>
</TR>
验证修改的页面是否存在错误:
在浏览器中刷新页面查看。
简化抽取Action类,让Action类继承BaseAction:
优点:
(1)使得全部Action都继承ActionSupport。
(2)实现模型驱动的接口所有放置到BaseAction类中完成。
(3)将Action传递值的操做封装到BaseAction中完成
第一步:在cn.itcast.storemanager.web.action中建立BaseAction的类:代码:
//action的父类:用来存放action的重复代码的
//通用:泛型
public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T>{
//实例化数据模型T,模型驱动必须实例化
// private T t = new T();
//子类可见
protected T model;//没有初始化
public T getModel() {
return model;
}
//在默认的构造器初始化数据模型
public BaseAction() {
//在子类初始化的时候,默认会调用父类的构造器
//反射机制:获取具体的类型
//获得带有泛型的类型,如BaseAction<Userinfo>
Type superclass = this.getClass().getGenericSuperclass();
//转换为参数化类型
ParameterizedType parameterizedType = (ParameterizedType) superclass;
//获取泛型的第一个参数的类型类,如Userinfo
Class<T> modelClass = (Class<T>) parameterizedType.getActualTypeArguments()[0];
//实例化数据模型类型
try {
model = modelClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//封装值栈的操做的方法
//root栈:栈顶map,能够经过key获取value
protected void setToValueStackRoot(String key,Object value){
ActionContext.getContext().getValueStack().set(key, value);
}
//root栈:栈顶对象(匿名)
protected void pushToValueStackRoot(Object value){
ActionContext.getContext().getValueStack().push(value);
}
//map栈:--推荐,能够经过key获取value
protected void putToValueStackMap(String key,Object value){
ActionContext.getContext().put(key, value);
}
//root栈:action的属性
protected Object result;
public Object getResult() {//action在root栈,所以,result也在root栈
return result;
}
}
第二步:建立UserAction子类代码:用来接收页面传递的user_login。
//用户操做的action
//public class UserAction extends ActionSupport implements ModelDriven<Userinfo>{
public class UserAction extends BaseAction<Userinfo>{
// //数据模型对象,在BaseAction中体现
// private Userinfo userinfo = new Userinfo();
// @Override
// public Userinfo getModel() {
// return userinfo;
// }
//注入service
private IUserService userService;
public void setUserService(IUserService userService) {
this.userService = userService;
}
//业务方法:登陆
public String login(){
System.out.println("用户开始登陆了。。。。"+model);
//调用业务层,查询
Userinfo loginUser= userService.login(model);
if(loginUser == null){
//登陆失败
//将失败信息打印页面
addActionError(this.getText("UserAction.loginerror"));
//跳转到登陆
return "loginjsp";
}else{
//登陆成功
//将登陆用户放入session
// ServletActionContext.getRequest().getSession().setAttribute("loginUser", loginUser);
ServletUtils.setLoginUserToSession(loginUser);
//代码:能够抽取到baseAction,也能够抽取到工具类中
//跳转到主页
return SUCCESS;
}
}
}
简单分析:
当子类实例化的时候,会将具体的类型来代替参数化父类的T,并自动执行父类的构造方法,经过反射机制,获得具体的模型的实例。struts经过getModel获得模型对象。
开发小技巧:
第三步:在cn.itcast.storemanager.utils包中抽取工具类ServletUtils.java:
//操做servlet相关
public class ServletUtils {
//登陆用户的key
private static final String LOGIN_USER="loginUser";//常量
//将登录了用户放入session
//知足登陆和退出
public static void setLoginUserToSession(Userinfo loginUser){
// ServletActionContext.getRequest().getSession().setAttribute("loginUser", loginUser);
if(null==loginUser){
//清除登陆用户
ServletActionContext.getRequest().getSession().removeAttribute(LOGIN_USER);
}else{
//放登陆用户
ServletActionContext.getRequest().getSession().setAttribute(LOGIN_USER, loginUser);
}
}
//从session获取登陆用户信息
public static Userinfo getLoginUserFromSession(){
// return (Userinfo)ServletActionContext.getRequest().getSession().getAttribute("loginUser");
Object o = ServletActionContext.getRequest().getSession().getAttribute(LOGIN_USER);
return o == null?null:(Userinfo)o;
}
}
第一步:设计新增父类Service,用于存放未来可能抽取出来的代码:
//业务层的父类:用来复用公用代码
//抽象类
public abstract class BaseService {
}
第二步:编写具体业务接口service
public interface IUserService {
/**
* 用户登陆操做
*/
Userinfo login(Userinfo userInfo);
}
第三步:编写具体业务接口的实现类UserServiceImpl.java
//继承BaseService:能够代码复用
//实现UserService:用来实现业务逻辑操做
public class UserServiceImpl extends BaseService implements IUserService {
//注入dao
// private UserDAO userDAO;
//注入用户操做的dao
private IGenericDao<Userinfo, String> userDao;//具体类型的dao了
public void setUserDao(IGenericDao<Userinfo, String> userDao) {
this.userDao = userDao;
}
//登陆验证,使用用户名和密码做为查询条件,查询对应的惟一对象,若是有存在则返回,不存在返回null
public Userinfo login(Userinfo userInfo) {
//调用dao
//QBC
//离线条件
DetachedCriteria criteria =DetachedCriteria.forClass(Userinfo.class)
.add(Restrictions.eq("name", userInfo.getName()))
.add(Restrictions.eq("password", userInfo.getPassword()));
List<Userinfo> list = userDao.findByCriteria(criteria);
return list.isEmpty()?null:list.get(0);
}
}
第一步:在cn.itcast.storemanager.daol包中,通用数据接口IGenericDao.java代码:
//通用DAO接口:为了简化代码开发
public interface IGenericDao<T,ID extends Serializable> {
/**
* 保存数据
* @param domain
*/
public void save(Object domain);
/**
* 更新
* @param domain
*/
public void update(Object domain);
/**
* 删除
* @param domain
*/
public void delete(Object domain);
/**
* 根据id查询对象
* @param domainClass
* @param id
* @return
*/
public T findById(Class<T> domainClass, ID id);
/**
* 查询全部
* @return
*/
public List<T> findAll(Class<T> domainClass);
//复杂条件查询
/**
* 命名查询
* @param queryName
* @param values
* @return
*/
public List<T> findByNamedQuery(String queryName, Object... values);
/**
* 离线条件查询
* @param criteria
* @return
*/
public List<T> findByCriteria(DetachedCriteria criteria);
}
第二步:在cn.itcast.storemanager.dao.impl包中通用数据接口实现类GenericDaoImpl.java代码
//通用dao的实现
//hibernate模版类操做,继承daosupport类
public class GenericDaoImpl<T,ID extends Serializable> extends HibernateDaoSupport implements IGenericDao<T, ID> {
//保存对象
public void save(Object domain) {
getHibernateTemplate().save(domain);
}
//修改对象
public void update(Object domain) {
getHibernateTemplate().update(domain);
}
//删除对象
public void delete(Object domain) {
getHibernateTemplate().delete(domain);
}
//使用主键ID查询
public T findById(Class<T> domainClass, ID id) {
return getHibernateTemplate().get(domainClass, id);
}
//查询全部
public List<T> findAll(Class<T> domainClass) {
return getHibernateTemplate().loadAll(domainClass);
}
//命名查询
public List<T> findByNamedQuery(String queryName, Object... values) {
return getHibernateTemplate().findByNamedQuery(queryName, values);
}
//QBC
public List<T> findByCriteria(DetachedCriteria criteria) {
return getHibernateTemplate().findByCriteria(criteria);
}
}
开发小技巧:
附加:若是开发中使用命名查询,能够在hbm文件中配置命名查询语句 (Userinfo.hbm.xml)
<!-- 使用命名查询 -->
<query name="Userinfo.login">
from Userinfo where name = ? and password = ?
</query>
配置几个:页面跳转、国际化、struts二、Spring核心配置文件。
第一步:配置 struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--
开发者模式:关闭:反作用:若是是ajax请求的状况下,一旦出错,不会在页面上打印错误
因此采用struts.i18n.reload和struts.configuration.xml.reload的模式
-->
<!-- <constant name="struts.devMode" value="true" /> -->
<!-- 不用重启服务器 -->
<constant name="struts.i18n.reload" value="true" />
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 表单样式 -->
<constant name="struts.ui.theme" value="simple" />
<!-- 加载src下的国际化文件messages.properties -->
<constant name="struts.custom.i18n.resources" value="messages" />
<package name="default" namespace="/" extends="struts-default">
<!-- 用户管理相关 -->
<!-- <action name="user_*" class="cn.itcast.storemanager.web.action.UserAction" method="{1}"> -->
<action name="user_*" class="userAction" method="{1}">
<result name="loginjsp">/login.jsp</result>
<result type="redirect">/jsps/main.jsp</result>
</action>
</package>
</struts>
第二步:在src下配置messages.properties
UserAction.loginerror=\u60A8\u8F93\u5165\u7684\u7528\u6237\u540D\u6216\u5BC6\u7801\u4E0D\u6B63\u786E
显示:
第三步:配置applicationContext.xml
(1)事务管理中增长login方法的事务控制:
<!-- 配置事务 -->
<!-- 配置事务管理器平台 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 事务管理通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" read-only="false"/>
<tx:method name="update*" read-only="false"/>
<tx:method name="delete*" read-only="false"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="login" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 切入点和切面 -->
<aop:config>
<aop:pointcut expression="bean(*Service)" id="txPointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
(2)三层的Bean配置:
<!--通用的DAO类 -->
<bean id="userDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- service -->
<bean id="userService" class="cn.itcast.storemanager.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- action -->
<bean id="userAction" class="cn.itcast.storemanager.web.action.UserAction" scope="prototype">
<property name="userService" ref="userService"/>
</bean>
总体运行登陆测试:
在数据库中新增用户admin,密码admin,登陆测试功能。
分析:仓库表不依赖于其余表,是独立的单表操做。下面咱们实现仓库表的CRUD
为了实现业务,咱们要编写的内容:
通常开发功能基本三步:
页面---java代码逻辑—配置文件
页面:
第一步: 改造表单(/jsps/store/add.jsp):将页面改造 <s:form>
<s:form action="store_add" namespace="/" method="post" name="select">
</s:form>
<tr>
<td style="padding-left:10px;" colspan="2" align="left">
<font color="red">
<s:fielderror/>
<s:actionerror/>
</font>
</td>
</tr>
<tr>
<td>
仓库名称:
</td>
<td>
<s:textfield name="name" cssClass="tx"/>
</td>
</tr>
<tr>
<td>
仓库地址:
</td>
<td>
<s:textfield name="addr" cssClass="tx"/>
</td>
</tr>
<tr>
<td>
库管员:
</td>
<td>
<s:textfield name="manager" cssClass="tx"/>
</td>
</tr>
测试:
刷新页面,看是否添加页面显示正常。
第二步: 编写服务器端java代码
编写逻辑分析:咱们的目标是增删改查:
第三步:编写StoreAction:
//仓库管理的action
public class StoreAction extends BaseAction<Store>{
//注入service
private IStoreService storeService;
public void setStoreService(IStoreService storeService) {
this.storeService = storeService;
}
//保存仓库
@InputConfig(resultName="addInput")//用于指定input进行struts2的校验
public String add(){
//业务层保存操做
storeService.saveStore(model);
// return "listjsp";//跳转到列表
return "storelist";//先查列表//使用重定向技术
}
}
第四步:编写IStoreService 接口
//仓库的业务层接口
public interface IStoreService {
/**
* 保存仓库
* @param store
*/
public void saveStore(Store store);
}
第五步:编写StoreServiceImpl 代码
//仓库管理的业务层实现
public class StoreServiceImpl extends BaseService implements IStoreService{
//注入dao
private IGenericDao<Store, String> storeDao;
public void setStoreDao(IGenericDao<Store, String> storeDao) {
this.storeDao = storeDao;
}
//@CacheEvict(value="storemanager",allEntries=true)//清除缓存区域的全部对象
public void saveStore(Store store) {
storeDao.save(store);
}
第六步: 配置struts.xml
<!-- 仓库管理相关 -->
<action name="store_*" class="storeAction" method="{1}">
<!-- 列表页面 -->
<result name="listjsp">/jsps/store/store.jsp</result>
<!-- 列表查询action -->
<result name="storelist" type="redirectAction">store_list</result>
<!-- 添加仓库 -->
<result name="addInput">/jsps/store/add.jsp</result>
</action>
第七步:配置applicationContext.xml
<!--通用的DAO类 -->
<bean id="userDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="storeDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- service -->
<bean id="userService" class="cn.itcast.storemanager.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="storeService" class="cn.itcast.storemanager.service.impl.StoreServiceImpl">
<property name="storeDao" ref="storeDao"/>
</bean>
<!-- action -->
<bean id="userAction" class="cn.itcast.storemanager.web.action.UserAction" scope="prototype">
<property name="userService" ref="userService"/>
</bean>
<bean id="storeAction" class="cn.itcast.storemanager.web.action.StoreAction" scope="prototype">
<property name="storeService" ref="storeService"/>
</bean>
注意:Action是多例。
第八步:表单校验
局部校验: Action所在包 "Action类名-<action>标签name属性-validation.xml"。
(1)新建xml文件:
引入配置文件头部:
位置:xwork-core-2.3.15.3.jar中的xwork-validator-1.0.3.dtd中
详细验证规则能够参考:
(2)配置:StoreAction-store_add-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<!-- 仓库的名称 -->
<field name="name">
<field-validator type="requiredstring">
<message key="StoreAction.name.required"/>
</field-validator>
</field>
<!-- 仓库的地址 -->
<field name="addr">
<field-validator type="requiredstring">
<message key="StoreAction.addr.required"/>
</field-validator>
</field>
<!-- 仓库的管理员 -->
<field name="manager">
<field-validator type="requiredstring">
<message key="StoreAction.manager.required"/>
</field-validator>
</field>
</validators>
(2)修改messages.properties
UserAction.loginerror=\u60A8\u8F93\u5165\u7684\u7528\u6237\u540D\u6216\u5BC6\u7801\u4E0D\u6B63\u786E
StoreAction.name.required=\u4ED3\u5E93\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
StoreAction.addr.required=\u4ED3\u5E93\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A
StoreAction.manager.required=\u4ED3\u5E93\u7684\u7BA1\u7406\u5458\u4E0D\u80FD\u4E3A\u7A7A
视图查看:
(5)在add.jsp页面中 添加 <s:fielderror> 回显标签。
<tr>
<td style="padding-left:10px;" colspan="2" align="left">
<font color="red">
<s:fielderror/>
<s:actionerror/>
</font>
</td>
</tr>
另外,还须要配置校验错误的默认返回的input结果集。
<!-- 仓库管理相关 -->
<action name="store_*" class="storeAction" method="{1}">
<!-- 列表页面 -->
<result name="storelist">/jsps/store/store.jsp</result>
<!-- 列表查询action -->
<result name="listjsp" type="redirectAction">store_list</result>
<!-- 添加仓库 校验出错跳转的页面-->
<result name="input">/jsps/store/add.jsp</result>
</action>
重启服务进行测试:
分别不填写和填写仓库信息,看是否能正常保存到数据库。
添加一条数据,到数据库查看是否存在。
流程:点击查看仓库 跳转store_list.action 先查询 到jsp显示。
第一步:先修改左侧导航菜单的连接:修改main.jsp
在main.jsp中引入struts2的标签库,将仓库管理链接的普通标签改成struts2标签:
<s:a namespace="/" action="store_list.action" target="content" id="left1002">[仓库管理]</s:a>
第二步:在StoreAction 添加 list查询方法
//仓库管理的action
public class StoreAction extends BaseAction<Store>{
//注入service
private IStoreService storeService;
public void setStoreService(IStoreService storeService) {
this.storeService = storeService;
}
//保存仓库
@InputConfig(resultName="addInput")//用于指定input进行struts2的校验
public String add(){
//业务层保存操做
storeService.saveStore(model);
// return "listjsp";//跳转到列表
return "storelist";//先查列表
}
//列表查询仓库
public String list(){
List<Store> list = storeService.findAllStore();
//将list放入map栈
putValueStackMap("list", list);
//返回列表页面
return "storejsp";
}
}
提示:记得将save的Action的返回结果修改回storelist。
第三步:修改IStoreService接口
/**
* 查询全部仓库列表
* @return
*/
public List<Store> findAllStore();实现
第四步:修改StoreServiceImpl类
public List<Store> findAllStore() {
return storeDao.findAll(Store.class);
}
修改列表页面store.jsp来回显数据
<tr style="background:#D2E9FF;text-align: center;">
<td>名称</td>
<td>地址</td>
<td>管理员</td>
<td>操做</td>
</tr>
<s:iterator value="#list" >
<tr>
<td><s:property value="name"/></td>
<td><s:property value="addr"/></td>
<td><s:property value="manager"/></td>
<td>
<s:a action="store_editview" namespace="/">
<s:param name="id" value="id"/>
修改
</s:a>
<s:a action="store_delete" namespace="/" cssClass="delLink">
<s:param name="id" value="id"/>
删除
</s:a>
</td>
</tr>
</s:iterator>
重启服务测试:
思路:根据主键id,拼接超连接来删除:<a href="….?id=xxx"> 删除 </a>
第一步:修改store.jsp 页面删除连接
<s:a action="store_delete" namespace="/" cssClass="delLink">
<s:param name="id" value="id"/>
删除
</s:a>
第二步:在StoreAction 添加delete 方法
//删除仓库
public String delete(){
//调用业务层
storeService.deleteStore(model);
//返回到列表
return "storelist";
}
第三步:IStoreService接口 代码
/**
* 根据id删除仓库
* @param store
*/
public void deleteStore(Store store);
第四步:StoreServiceImpl类的代码
public void deleteStore(Store store) {
storeDao.delete(store);
}
第五步:重启服务测试删除。
【提示】:若是部分较旧的浏览器可能会报js错误,那么换个较新的浏览器试试。
之后你们在开发过程当中,必定要注意浏览器的兼容性问题,在交付项目、上线以前,要用客户的所用的浏览器测试一下。
【思考】:
若是仓库中存在货物,可否删除 ???
可能没法删除,可能报错!!
缘由是:有主外键关联。
【功能优化】:
在页面添加 JS确认删除效果。
store.jsp
<s:a action="store_delete" onclick="return confirm('是否确认删除')">
分析修改,两步:须要先查询回显数据,再进行修改提交。
所以,功能开发须要分两部分:表单回显和更新提交。咱们分别来作。
第一部分:表单回显(查询)。
第一步:修改 store.jsp 修改超连接(参考删除)
<s:a action="store_editview" namespace="/">
<s:param name="id" value="id"/>
修改
</s:a>
第二步:在StoreAction 添加 editview 方法
//修改的回显
public String editview(){
//根据id查询出来数据,压入栈顶
Store store=storeService.findStoreById(model.getId());
pushToValueStackRoot(store);
//跳转到修改页面
return "editjsp";
}
第三步:业务层IStoreServcie接口:
/**
* 根据id查询仓库
* @param id
* @return
*/
public Store findStoreById(String id);
第四步:业务层StoreServcieImpl:
public Store findStoreById(String id) {
return storeDao.findById(Store.class, id);
}
第五步:配置struts.xml 跳转编辑页面
<!-- 仓库管理相关 -->
<action name="store_*" class="storeAction" method="{1}">
<!-- 列表页面 -->
<result name="listjsp">/jsps/store/store.jsp</result>
<!-- 列表查询action -->
<result name="storelist" type="redirectAction">store_list</result>
<!-- 添加仓库 -->
<result name="addInput">/jsps/store/add.jsp</result>
<!-- 修改页面 -->
<result name="editjsp">/jsps/store/edit.jsp</result>
<result name="editInput">/jsps/store/edit.jsp</result>
</action>
第六步:修改edit.jsp页面, 将<form> 改造为 <s:form>,使其拥有回显功能。
<s:form action="store_edit" namespace="/" method="post" name="select">
</s:form>
思考:修改表单和添加表单的区别是什么?
就差一个主键id。所以,修改须要隐藏一个id,用来传递id执行更新。
【补充】实际业务开发中,你能够将保存和修改页面用一个。(就根据判断页面有没有传过来id来判断是修改仍是保存)-课外补充-回去试试。
<tr>
<td bgcolor="a0c0c0" style="padding-left:10px;" colspan="2" align="left">
<b>修改新仓库:</b>
</td>
</tr>
<tr>
<td style="padding-left:10px;" colspan="2" align="left">
<font color="red">
<s:fielderror/>
<s:actionerror/>
</font>
</td>
</tr>
<tr>
<td>
仓库名称:
</td>
<td>
<s:textfield name="name" cssClass="tx"/>
<!-- id隐藏域 -->
<s:hidden name="id"/>
</td>
</tr>
<tr>
<td>
仓库地址:
</td>
<td>
<s:textfield name="addr" cssClass="tx"/>
</td>
</tr>
<tr>
<td>
库管员:
</td>
<td>
<s:textfield name="manager" cssClass="tx"/>
</td>
</tr>
第七步:回显阶段功能测试,测试点:
第二部分:数据更新提交。
第一步:在edit.jsp中编辑form表单
<s:form action="store_edit" namespace="/" method="post" name="select">
</s:form>
第二步:修改form 提交,StoreAction添加 edit方法
//修改仓库数据
@InputConfig(resultName="editInput")
public String edit(){
//将数据传入业务层
storeService.updateStore(model);
//跳转到列表页面
return "storelist";
}
第三步:业务层IStoreService代码
/**
* 更新仓库
* @param store
*/
public void updateStore(Store store);
第四步:业务层StoreServiceImpl.java
public void updateStore(Store store) {
//hibernate自动根据id来修改全部字段的
storeDao.update(store);
}
提示:
这里的修改直接调用update方法,得必须保证store的属性都有值。
第五步:测试修改功能。
功能优化补充:增长表单校验功能。
增长校验文件:(将添加的校验文件再复制一份,重命名为)
页面上增长:
<tr>
<td bgcolor="a0c0c0" style="padding-left:10px;" colspan="2" align="left">
<b>修改新仓库:</b>
</td>
</tr>
<tr>
<td style="padding-left:10px;" colspan="2" align="left">
<font color="red">
<s:fielderror/>
<s:actionerror/>
</font>
</td>
</tr>
发现问题:
若是修改方法也添加了校验, 默认跳转input视图, 但添加方法已经配置了input,怎么办?
解决办法:修改默认input视图,让修改和添加的校验失败后分别跳到不一样的input --------- @InputConfig,能够经过resultName属性指定不一样input的名称。
(1)修改storeAction,添加注解@InputConfig。
//保存仓库
@InputConfig(resultName="addInput")//用于指定input进行struts2的校验
public String add(){
//业务层保存操做
storeService.saveStore(model);
// return "listjsp";//跳转到列表
return "storelist";//先查列表
}
//修改仓库数据
@InputConfig(resultName="editInput")
public String edit(){
//将数据传入业务层
storeService.updateStore(model);
//跳转到列表页面
return "storelist";
}
配置struts.xml,分别对增长和修改配置不一样input视图 。
<!-- 仓库管理相关 -->
<action name="store_*" class="storeAction" method="{1}">
<!-- 列表页面 -->
<result name="listjsp">/jsps/store/store.jsp</result>
<!-- 列表查询action -->
<result name="storelist" type="redirectAction">store_list</result>
<!-- 添加仓库 -->
<result name="addInput">/jsps/store/add.jsp</result>
<!-- 修改页面 -->
<result name="editjsp">/jsps/store/edit.jsp</result>
<result name="editInput">/jsps/store/edit.jsp</result>
</action>
再次测试校验失败的页面跳转功能。
分析一下功能:
入库主要是将货物保存到仓库中,那么保存货物是须要选择仓库的,所以,下面咱们在作入库功能以前,先要实现仓库列表的显示。
点击【入库】
【分析】
有两种方案:
<!-- ongl表达式获取列表(list中是不少map)将List<Store> 存放到map栈,命名为storeList -->
<s:select list="#storeList" name="storeId" id="storeId" listKey="id" listValue="name"></s:select>
2.将下拉列表当作一个独立组件,该组件的数据独立加载,和外面的业务无关。
这里采用第二种方式。
选择仓库列表,一般更多使用Ajax交互获取。
异步交互:(json和xml) 最经常使用的数据格式 json ({key:value} 对象, [elements] 数组 )
第一步:在系统页面 导入jQuery
/jsps/save/save.jsp 入库页面
<!-- 引入jquery库 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.8.3.js"></script>
第二步: 基于一个事件,发生Ajax请求 :(这里是页面加载后填充列表数据---你们也可使用点击事件)
Jquery Ajax 最经常使用的两个操做 $.get 、$.post (若是有参数,则须要用post;没有参数,则随意,通常咱们都用post)
咱们这里能够省略请求参数和返回内容格式,只须要请求地址和回调函数便可,代码以下:
<script type="text/javascript">
$(function(){
//页面加载后,发生ajax请求
/**
url,[data],[callback],[type]String,Map,Function,String
url:发送请求地址。
data:待发送 Key/value 参数。请求的数据
callback:发送成功时回调函数。
type:返回内容格式,xml, html, script, json, text, _default。
*/
$.post("${pageContext.request.contextPath}/store_listAjax.action",function(data){
//data是服务器返回的内容(本来是json字符串),通过转换后的对象(js对象或js数据对象)。
});
});
</script>
第三步: 服务器处理数据,将处理结果生成json,返回客户端。
分析:其实这个异步请求仓库数据的方法与查询全部仓库数据的方法基本是一致的,只是返回结果不一样。一个是返回List集合到跳转页面,一个是返回json字符串。
在StoreAction 添加 listAjax方法:
public String listAjax(){
return "listajax";
}
那么如何将查询结果转换为json?
可使用struts2提供json插件包(struts2-json-plugin.jar),完成值栈中数据,到json转换返回。
手动导入插件包:
查看 struts-plugin.xml(了解插件的基本做用)
该插件编写一个新的package (json-default) ,而且内部提供 json 结果集类型 ,只要使用json结果集类型,struts2 将数据转换为json格式返回客户端 !
编写StoreAction,将查询的集合存放到root栈的result属性中。
//查询全部列表(给异步请求用的)
public String listAjax(){
//查询全部仓库,返回list
List<Store> storeList = storeService.findAllStore();
//怎样让list转化成json?
/**
* 第一步: struts2-json-plugin-2.3.15.3.jar
* 第二步:修改struts.xml配置:<package name="default" namespace="/" extends="json-default">
* 第三步:修改struts.xml文件:添加返回值:<result name="listajax" type="json"></result>
* 第四步:将list压入栈顶
* */
pushValueStackRoot(storeList);
return "listajax";
}
在struts.xml 配置结果集:
更改默认包:(要求咱们的包去继承json-default包)
<package name="default" namespace="/" extends="json-default">
</package>
思考:
咱们要将哪些数据转换为json?
分析一下JsonResult(org.apache.struts2.json.JSONResult) 源码,关联struts2源码来查看(课件中的SSH整合原始包中有相应zip包):
====================================================================
转换成json
若是为结果集配置root参数,去值栈找root参数值对应对象,转换为json返回,若是没有配置root参数, 将root栈的顶部对象返回(默认model在栈顶,若是没有model,则action在栈顶) !
struts.xml
<!-- 仓库管理相关 -->
<action name="store_*" class="storeAction" method="{1}">
<!-- 列表页面 -->
<result name="listjsp">/jsps/store/store.jsp</result>
<!-- 列表查询action -->
<result name="storelist" type="redirectAction">store_list</result>
<!-- 添加仓库 -->
<result name="addInput">/jsps/store/add.jsp</result>
<!-- 修改页面 -->
<result name="editjsp">/jsps/store/edit.jsp</result>
<result name="editInput">/jsps/store/edit.jsp</result>
<!-- json结果集类型 -->
<result name="listajax" type="json">
</result>
</action>
测试调试:
经过firebug抓包工具查看数据是否返回 !
提示:若是配置的是开发者模式,则这里会返回200,而不是错误500。
控制台打印了异常:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.itcast.storemanager.domain.Store.goodses, no session or session was closed
缘由是:查询store的时候,其集合属性goods默认是延迟加载的,而store返回到表现层action的时候,事务已经在service层结束了,也说明链接和session关了。
思考:能够用OpenSessionInView么?
能够解决报错,但不合适,由于,咱们不须要goods关联集合属性的数据,只是须要store便可。性能会下降。
解决方案: 使用@JSON注解,排除不须要转的属性 --- 添加getXxx方法上:
在Store的po类上的getGoodses上添加注解:表示注解排除不须要转换成json的属性数据,即Store对象关联的Goods对象集合。
//表示注解排除不须要转换成json的属性数据
@JSON(serialize=false)
public Set getGoodses() {
return this.goodses;
}
正确
第四步: 完善ajax代码:编写客户端回调函数,处理返回数据
给select列表元素增长id属性,用于选择这个select:
<tr>
<td>
选择仓库:
</td>
<td>
<select class="tx" style="width:120px;" name="store.id" id="store_id">
</select>
(此信息从数据库中加载)
</td>
</tr>
【回顾知识点】咱们前台页面拿到的是个数组,那么如何在jQuery中遍历数组:
第五步:加载仓库的异步请求代码:
<!-- 引入jquery库 -->
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.8.3.js"></script>
<script type="text/javascript">
//onload
$(function(){
//dom初始化后加载
//$.post(请求url,请求参数,回调函数,返回的类型);
$.post("${pageContext.request.contextPath}/store_listAjax.action",function(data){
//data:转换后的对象:json对象数组-dom对象
$(data).each(function(){
//this每个对象json
//this.id
var option=$("<option value='"+this.id+"'>"+this.name+"</option>");
//添加到下拉列表中
$("#store_id").append(option);
});
});
});
</script>
业务问题:若是仓库不常常变更,大量进出库,老是须要查询仓库列表 (列表重复) ,使用缓存优化 !
spring缓存的配置原理:(注解)
第一步: 导入ehcache的jar 和 ehcache.xml
ehcache-core-2.6.6.jar
spring-context-support.jar (spring支持jar,包含平台缓存管理器)
第二步:在resources下建立ehcache.xml文件,配置自定义的缓存名称<cache name="storemanager">
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="storemanager"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
第三步: 配置Spring的applicationContext.xml
引用cache 名称空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
第四步:注解方式完成配置:(重点)
两步:
<!-- 配置缓存整合 -->
<!-- ehcache管理器对象 -->
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<!-- 默认读取classpath:ehcache.xml -->
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
<!-- 具体的平台缓存管理器 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<!-- 注入ehcache -->
<property name="cacheManager" ref="ehCacheManager"/>
</bean>
<!-- 缓存注解驱动 -->
<cache:annotation-driven cache-manager="cacheManager"/>
(2)在StoreServiceImpl.java类中,使用注解开启缓存
代码:
查询方法须要从缓存中查询
@Cacheable(value="storemanager")//放入缓存
public List<Store> findAllStoreList() {
return storeDao.findAll(Store.class);
}
增删改方法能够清理缓存
@CacheEvict(value="storemanager",allEntries=true)//清除缓存区域的全部对象
public void saveStore(Store store) {
storeDao.save(store);
}
【扩展】,可将不一样业务放置到不一样的缓存,好比,将系统参数、分类,货物、仓库。。。。