SSH综合练习-仓库管理系统-第一天
综合练习的整体目的:
整合应用 Struts2 、Hibernate、Spring 、Mysql 、 jQuery Ajax、java基础知识
-
熟悉企业SSH 基础架构
-
掌握在SSH基础架构 进行CRUD 编写(抽取代码) (单表、多表 )
-
JQuery Ajax 编程实现(struts2整合json的插件包)
今天的主要内容:
-
开发前的准备工作(原型导入、需求功能分析)
-
开发基础环境的搭建(SSH环境搭建、MyEclipse逆向生成实体类和映射)
-
登录功能的实现(三层架构搭建、通用代码抽取、基于泛型的通用DAO)
-
仓库管理功能的实现(单表的CRUD、值栈的使用、其他代码抽取)
-
货物管理功能的实现-入库(仓库列表的AJAX请求,Spring和Ehcache缓存集成)
-
开发前的准备工作
-
原型(静态页面)导入
-
原型就是软件的一个早期可运行的版本,它实现了目标系统的某些功能,主要用于和用户确定其明确的需求。以及开发编码的基础页面。
原型:低精度+高精度
-
低精度:原型页面粗糙,只是功能演示,不能作为开发使用。功能参考。
-
高精度:原型页面精美,达到将来产品的效果。可以作为开发使用。
我们这里提供的原型就是仓库管理系统静态页面的工程。
【思考】
如何导入原型工程?
-
开发工具自动导入
-
手动分类导入-推荐
新建Web项目storemanager:
导入静态页面和源码配置等:
页面赋值到WebRoot,源码和配置复制到src
【提示】
复制的时候,不要覆盖WEB-INF和META-INF目录。
【部署测试】
将工程部署到tomcat中,启动服务器,查看是否正常能访问。
-
需求功能分析
详细功能可以参考需求文档,也可以查看原型来了解。
要开发的功能如下:
-
登录功能 (搭建项目基础架构 ) ---- userinfo用户表
-
仓库管理 (仓库信息增删改查) ----- store仓库表
-
货物进出库 (货物的存入仓库、 离开仓库 ) ---- goods货物表
-
库存管理 (查看仓库中货物情况-盘点 )
-
历史记录查询 (将货物进出库进行记录操作 )---- history 历史记录表
数据表:
表之间的关系:
表之间的关系:
用户表: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 |
double |
yes |
余量 |
||
6 |
_user |
varchar |
50 |
yes |
操作人(Session中获取),直接保存名称,不引用userinfo表 |
-
数据库生成
Mysql:
使用一个用户,建一个数据库,将脚本在该数据库上运行,建立相应的表。
步骤:
-
新建用户store
在Add User页面中,用户名和密码都是store
-
新建数据库itcaststore
登录之后:
-
选中数据库itcaststore,将sql\mysql\store.sql脚本粘贴过来,执行:创建4张表。
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环境搭建、MyEclipse逆向生成实体类和映射)
技术选型:要用什么技术组件(ssh+mysql)
-
SSH开发环境构建
方式:引入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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<filter>
<filter-name>struts2filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilterfilter-class>
filter>
<filter-mapping>
<filter-name>struts2filter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<welcome-file-list>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
web-app>
第三步:导入配置文件:
通常实际项目开发时 : "项目源码、测试代码、配置文件" 一般是分开的,所以我们首先来规划一下源码文件夹。
新建源码文件夹:
命名为resource(用来存放资源文件)
命名为test(用来存放测试文件)
我们可以新建不同功能的源代码文件夹:
将配置文件都复制到resources。
最终结果:
其中:
-
db.properties文件:
jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql:///itcaststore
jdbc.username = store
jdbc.password = store
-
log4j.properties文件
### 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
-
messages.properties
国际化资源文件:用来实现项目的国际化
-
struts.xml
xml version="1.0" encoding="UTF-8" ?>
DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.i18n.reload" value="true" />
<constant name="struts.configuration.xml.reload" value="true" />
<constant name="struts.ui.theme" value="simple" />
<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>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialectprop>
<prop key="hibernate.hbm2ddl.auto">updateprop>
<prop key="hibernate.show_sql">trueprop>
<prop key="hibernate.format_sql">trueprop>
props>
property>
<property name="mappingLocations">
<list>
<value>classpath:cn/itcast/storemanager/domain/*.hbm.xmlvalue>
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>
-
使用myeclipse反向生成功能
不建议在原来项目上生成 ,新建web 项目abcdefg,用来保存生成的po类和hbm。
点击:
切换Database Explorer 视图,
新建数据库连接
选择Myeclipse视图,选择abcdefg项目,对abcdefg项目添加hibernate支持
选择Hibernate的版本
点击下一步:选择DB Driver
选择abcdefg项目,创建包cn.itcast.storemanager.domain用来存放持久化对象和配置文件。
回到数据透视图,选择表,进行反转生成
配置选项
注意:两点:
-
-
包名的问题,最好实际项目用的什么包名,这里就指定什么包名。
-
xml配置的话必须选择java类的选项
修改applicationContext.xml 引入hbm映射
<property name="mappingResources">
<list>
<value>cn/itcast/storemanager/domain/Goods.hbm.xmlvalue>
<value>cn/itcast/storemanager/domain/History.hbm.xmlvalue>
<value>cn/itcast/storemanager/domain/Store.hbm.xmlvalue>
<value>cn/itcast/storemanager/domain/Userinfo.hbm.xmlvalue>
list>
property>
最后:测试实体类是否正常:
删除数据库表,重启服务,看是否报错和自动生成表。
【扩展知识】批量映射配置:
<property name="mappingLocations">
<list>
<value>classpath:cn/itcast/storemanager/domain/*.hbm.xmlvalue>
list>
property>
-
登录功能的实现(三层架构搭建、通用代码抽取、基于泛型的通用Dao)
【业务逻辑梳理】
用户在页面输入用户和密码 -----> 数据封装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;">
注意: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">
font>
TD>
TR>
验证修改的页面是否存在错误:
在浏览器中刷新页面查看。
-
编写UserAction (表现层 )
简化抽取Action类,让Action类继承BaseAction:
优势:
(1)使得所有Action都继承ActionSupport。
(2)实现模型驱动的接口全部放置到BaseAction类中完成。
(3)将Action传递值的操作封装到BaseAction中完成
第一步:在cn.itcast.storemanager.web.action中创建BaseAction的类:代码:
//action的父类:用来存放action的重复代码的
//通用:泛型
public abstract class BaseAction
//实例化数据模型T,模型驱动必须实例化
// private T t = new T();
//子类可见
protected T model;//没有初始化
public T getModel() {
return model;
}
//在默认的构造器初始化数据模型
public BaseAction() {
//在子类初始化的时候,默认会调用父类的构造器
//反射机制:获取具体的类型
//得到带有泛型的类型,如BaseAction
Type superclass = this.getClass().getGenericSuperclass();
//转换为参数化类型
ParameterizedType parameterizedType = (ParameterizedType) superclass;
//获取泛型的第一个参数的类型类,如Userinfo
Class
//实例化数据模型类型
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
public class UserAction extends BaseAction
// //数据模型对象,在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得到模型对象。
开发小技巧:
-
可以先将代码写完再统一配置(因为配置的时候需要代码)
-
代码可以从前往后写(从页面-->Action-->Service-->Dao),也可以从后往前写(先写Dao,再写Action和Service)。
第三步:在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;
}
}
-
编写UserService (业务层 )
第一步:设计新增父类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
public void setUserDao(IGenericDao
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
return list.isEmpty()?null:list.get(0);
}
}
-
编写GenericDao 通用Dao (数据层)
第一步:在cn.itcast.storemanager.daol包中,通用数据接口IGenericDao.java代码:
//通用DAO接口:为了简化代码开发
public interface IGenericDao
/**
* 保存数据
* @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
/**
* 查询所有
* @return
*/
public List
//复杂条件查询
/**
* 命名查询
* @param queryName
* @param values
* @return
*/
public List
/**
* 离线条件查询
* @param criteria
* @return
*/
public List
}
第二步:在cn.itcast.storemanager.dao.impl包中通用数据接口实现类GenericDaoImpl.java代码
//通用dao的实现
//hibernate模版类操作,继承daosupport类
public class GenericDaoImpl
//保存对象
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
return getHibernateTemplate().get(domainClass, id);
}
//查询所有
public List
return getHibernateTemplate().loadAll(domainClass);
}
//命名查询
public List
return getHibernateTemplate().findByNamedQuery(queryName, values);
}
//QBC
public List
return getHibernateTemplate().findByCriteria(criteria);
}
}
开发小技巧:
-
抽取代码的时候,也可以从实现类往接口上抽取。
-
抽取代码相对比较复杂一点,但只需要写一次,就可以供所有业务使用,说白了,就是实现了对通用方法的封装,不用每次在不同的Dao中写重复的代码。
附加:如果开发中使用命名查询,可以在hbm文件中配置命名查询语句 (Userinfo.hbm.xml)
<query name="Userinfo.login">
from Userinfo where name = ? and password = ?
query>
-
统一配置(struts.xml,message.properties,applicationContext.xml)
配置几个:页面跳转、国际化、struts2、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>
<constant name="struts.i18n.reload" value="true" />
<constant name="struts.configuration.xml.reload" value="true" />
<constant name="struts.ui.theme" value="simple" />
<constant name="struts.custom.i18n.resources" value="messages" />
<package name="default" namespace="/" extends="struts-default">
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配置:
<bean id="userDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
bean>
<bean id="userService" class="cn.itcast.storemanager.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
bean>
<bean id="userAction" class="cn.itcast.storemanager.web.action.UserAction" scope="prototype">
<property name="userService" ref="userService"/>
bean>
整体运行登录测试:
在数据库中新增用户admin,密码admin,登录测试功能。
-
仓库管理功能的实现(单表的CRUD)
分析:仓库表不依赖于其他表,是独立的单表操作。下面我们实现仓库表的CRUD
为了实现业务,我们要编写的内容:
-
仓库添加功能
一般开发功能基本三步:
页面---java代码逻辑—配置文件
页面:
第一步: 改造表单(/jsps/store/add.jsp):将页面改造
<s:form action="store_add" namespace="/" method="post" name="select">
<tr>
<td style="padding-left:10px;" colspan="2" align="left">
<font color="red">
<s:fielderror/>
<s:actionerror/>
font>
td>
tr>
<tr>
<td>
仓库名称:
td>
<td>
td>
tr>
<tr>
<td>
仓库地址:
td>
<td>
td>
tr>
<tr>
<td>
库管员:
td>
<td>
td>
tr>
测试:
刷新页面,看是否添加页面显示正常。
第二步: 编写服务器端java代码
编写逻辑分析:我们的目标是增删改查:
-
增加、删除、修改 -----> 重定向查询的Action
-
查询的Action(重新查询数据) -----> 转发列表jsp页面
第三步:编写StoreAction:
//仓库管理的action
public class StoreAction extends BaseAction
//注入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
public void setStoreDao(IGenericDao
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.jspresult>
<result name="addInput">/jsps/store/add.jspresult>
第七步:配置applicationContext.xml
<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>
<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>
<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类名-
(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页面中 添加
<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.jspresult>
<result name="listjsp" type="redirectAction">store_listresult>
重启服务进行测试:
分别不填写和填写仓库信息,看是否能正常保存到数据库。
添加一条数据,到数据库查看是否存在。
-
仓库列表查询功能
流程:点击查看仓库 跳转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
//注入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
//将list放入map栈
putValueStackMap("list", list);
//返回列表页面
return "storejsp";
}
}
提示:记得将save的Action的返回结果修改回storelist。
第三步:修改IStoreService接口
/**
* 查询所有仓库列表
* @return
*/
public List
第四步:修改StoreServiceImpl类
public List
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>
<td>
<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,拼接超链接来删除: 删除
第一步:修改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
-
仓库修改功能
分析修改,两步:需要先查询回显数据,再进行修改提交。
因此,功能开发需要分两部分:表单回显和更新提交。我们分别来做。
第一部分:表单回显(查询)。
第一步:修改 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.jspresult>
<result name="storelist" type="redirectAction">store_listresult>
<result name="addInput">/jsps/store/add.jspresult>
<result name="editInput">/jsps/store/edit.jspresult>
第六步:修改edit.jsp页面, 将