一、ERP项目
1.1 ERP简介
ERP是Enterprise Resource Planning(企业资源计划)的简称,是上个世纪90年代美国一家IT公司根据当时计算机信息、IT技术发展及企业对供应链管理的需求,预测在今后信息时代企业管理信息系统的发展趋势和即将发生变革,而提出了这个概念。 ERP是针对物资资源管理(物流)、人力资源管理(人流)、财务资源管理(财流)、信息资源管理(信息流)集成一体化的企业管理软件。它将包含客户/服务架构,使用图形用户接口,应用开放系统制作。除了已有的标准功能,它还包括其它特性,如品质、过程运作管理、以及调整报告等。
1.2 软件项目常识
1.2.1 软件生存周期模型
软件生存周期模型是描述软件开发过程中各种活动如何执行的模型。软件生存周期模型确立了软件开发和演绎中各阶段的次序限制以及各阶段或机动的准则,确立开发过程所遵守的规定和限制,便于各种活动的协调,便于各种人员的有效通信,有利于活动重用,有利于活动管理。常见的软件生存周期模型有瀑布模型、演化模型、螺旋模型、喷泉模型等。
1.2.2 瀑布模型
瀑布模型核心思想是按工序将问题化简,将功能的实现与设计分开,便于分工协作,即采用结构化的分析与设计方法将逻辑实现与物理实现分开。将软件生命周期划分为制定计划、需求分析、软件设计、程序编写、软件测试和运行维护等六个基本活动,并且规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落。
1.2.3 需求分析与需求说明书
所谓"需求分析",是指对要解决的问题进行详细的分析,弄清楚问题的要求,包括需要输入什么数据,要得到什么结果,最后应输出什么。可以说,在软件工程当中的“需求分析”就是确定要计算机“做什么”,要达到什么样的效果。可以说需求分析是做系统之前必做的。
需求规格说明书的编制是为了使用户和软件开发者双方对该软件的初始规定有一个共同的理解, 使之成为整个开发工作的基础。包含硬件、功能、性能、输入输出、接口需求、警示信息、保密安全、数据与数据库、文档和法规的要求。
( 请大家课后阅读《蓝云ERP需求规格说明书》了解需求 )
1.2.4 软件设计文档
软件设计是从软件需求规格说明书出发,根据需求分析阶段确定的功能设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及编写具体的代码,形成软件的具体设计方案。
软件设计文档分为《概要设计》和《详细设计》
概要设计:系统模块划分、网络拓扑图、用例图。
详细设计:类图、时序图、类清单、方法清单、接口清单、表结构文档。
1.2.5 UML语言
统一建模语言(UML,UnifiedModelingLanguage)是面向对象软件的标准化建模语言。UML因其简单、统一的特点,而且能表达软件设计中的动态和静态信息,目前已成为可视化建模语言的工业标准。
UML从考虑系统的不同角度出发,定义了用例图、类图、对象图、状态图、活动图、序列图、协作图、构件图、部署图等9种图。这些图从不同的侧面对系统进行描述。系统模型将这些不同的侧面综合成一致的整体,便于系统的分析和构造。尽管UML和其它开发工具还会设计出许多派生的视图,但上述这些图和其它辅助性的文档是软件开发人员所见的最基本的构造。
1.2.6 设计工具PowerDesigner(PD)
PowerDesigner(PD)最初由Xiao-Yun Wang(王晓昀)在SDP Technologies公司开发完成。是Sybase的企业建模和设计解决方案,采用模型驱动方法,将业务与IT结合起来,可帮助部署有效的企业体系架构,并为研发生命周期管理提供强大的分析与设计技术。PowerDesigner独具匠心地将多种标准数据建模技术(UML、业务流程建模以及市场领先的数据建模)集成一体,并与 .NET、WorkSpace、PowerBuilder、Java™、Eclipse 等主流开发平台集成起来,从而为传统的软件开发周期管理提供业务分析和规范的数据库设计解决方案。
1.3 软件设计
1.3.1 UML设计
1.3.1.1 用例图(User Case)
用例图是指由参与者(Actor)、用例(Use Case),边界以及它们之间的关系构成的,用于描述系统功能的视图。用例图是参与者所能观察到的系统功能的模型图。用例图是系统的蓝图。用例图呈现了一些参与者,一些用例,以及它们之间的关系,主要用于对系统、子系统或类的功能行为进行建模。
1.3.1.2 类图(Class Diagram)
类图是用于显示模型的静态结构,特别是模型中存在的类、类的内部结构以及它们与其他类的关系等。类图不显示暂时性的信息。类图是面向对象建模的主要组成部分。它既用于应用程序的系统分类的一般概念建模,也用于详细建模,将模型转换成编程代码。类图也可用于数据建模。
1.3.1.3 序列图(Sequence Diagram)
序列图是对对象之间传送消息的时间顺序的可视化表示。序列图的主要用途是把用例表达的需求,转化为进一步、更加正式层次的精细表达。用例常常被细化为一个或者更多的序列图。同时序列图更有效地描述如何分配各个类的职责以及各类具有相应职责的原因。
图:采购流程
图:销售流程
1.3.2 数据库设计
部门表(DEP)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
name varchar(30) 必填 名称
tele varchar(30) 电话
员工表(EMP)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
username varchar(15) 必填 登陆名
pwd varchar(32) 密码
name varchar(30) 真实姓名
gender number 性别
email varchar(255) 电子邮箱
tele varchar(30) 电话
address varchar(255) 地址
birthday date 出生年月日
depuuid number 部门编号
商品类型表(GOODSTYPE)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
name varchar(30) 必填 名称
商品表(GOODS)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
name varchar(30) 必填 商品名称
origin varchar(30) 产地
producer varchar(30) 厂商
unit varchar(30) 计量单位
inprice number(8,2) 进货价
outprice number(8,2) 销售价
goodstypeuuid number 商品类型ID
仓库表(STORE)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
name varchar(30) 必填 名称
empuuid number 库管员ID
供应商及客户表(SUPPLIER)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
name varchar(30) 必填 名称
address varchar(100) 地址
contact varchar(30) 联系人
tele varchar(30) 电话
email varchar(100) 电子邮箱
type number 类型
订单表(ORDERS)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
createtime date 创建日期
checktime date 审核日期
starttime date 确认日期
endtime date 结束日期
type char(1) 类型
creater number 创建人
checker number 审核人
starter number 确认人
ender number 结束人
supplieruuid number 供应商ID
totalmoney number 总金额
state char(1) 状态
订单明细表(ORDERDETAIL)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
goodsuuid number 商品ID
goodsname varchar(50) 商品名称
price number(10,2) 价格
num number 数量
money number(10,2) 金额
endtime date 结束日期
ender number 结束人
storeuuid number 仓库ID
state char(1) 状态
ordersuuid number 订单ID
商品仓库库存表(STOREDETAIL)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
storeuuid number 仓库ID
goodsuuid number 商品ID
num date 库存数量
商品仓库库存操作记录(STOREOPER)
字段名 类型(位数) 是否必填 说明
uuid number 必填 主键
empuuid number 员工ID
opertime date 操作时间
storeuuid number 仓库ID
goodsuuid number 商品ID
num number 操作数量
type char(1) 类型
1.4 系统架构
1.4.1 前后端开发
前端:包括HTML 、JS 、CSS 、图片 ,作用是展示数据和采集数据。
后端:数据访问层、业务逻辑层、控制层(Controller),作用处理业务逻辑、进行数据存储和读取。SSM+SpringBoot+Maven+Freemarker+SVN+POI+Javamail+shiro…
前后端开发的优点:
1)分工明确,有利于提高开发速度;
2)项目更换开发语言,工作量较少;
3)增强用户的体验;
前端:所关心的问题是如何展示数据和如何采集用户输入的数据。
后端:数据的逻辑处理。
1.4.2 前端easyui
对于企业级开发项目,或是网站的后台部分,我们可以使用前端框架来实现,现在目前比较主流的前端框架有easyUI BUI miniUI等。其中easyUI在企业开发中市场份额最大,应用最广泛,使用起来也比较容易上手。我们在本次项目中就采用 easyUI作为前端框架。
简介:easyui是一种基于jQuery的用户界面插件集合。使用easyui你不需要写很多代码,你只需要通过编写一些简单HTML标记,就可以定义用户界面。
easyui是个完美支持HTML5网页的完整框架。节省您网页开发的时间和规模,很简单但功能强大的。
我们在初学easyUI时,可以用到哪学到哪,我们在项目进展过程中或以查文档的方式,循序渐进地掌握easyUI。
推荐学习网址:http://www.jeasyui.net
1.4.3 后端-SSM继承框架
SSM即SpringMVC+spring +MyBatis。
SpringMVC : SpringMVC属于Spring的后续产品。Spring 框架提供了构建 Web 应用程序的全功能MVC模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架。
MyBatis: MyBatis是一个开放源代码的优秀的持久化框架,它支持定制化SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
配置方式
SSM作为我们后端最核心的框架,项目后期会添加shiro框架和activiti框架。
1.5 数据库:Oracle
Oracle是由甲骨文公司开发出来的,并于1989年正式进入中国市场,成为第一家进入中国的世界软件巨头。当然,当时的Oracle尚名不见经传,由Oracle开发的商用关系型数据库技术即年开始服务于中国用户。1991年7月,Oracle在北京建立独资公司。
Oracle数据库,使积聚了众多领先性的数据库系统,在集群技术、高可用性、商业智能、安全性、系统管理等方面都领跑业界。
1.6 开发工具和开发环境
1.6.1 Eclipse初始环境配置
设定字符集为UTF-8
1.6.2 搭建Maven环境
略。
二、SSM框架搭建
2.1 项目搭建步骤
第一步:创建Maven父工程
第二步:添加依赖
打开pom.xml文件,然后添加以下JAR包的依赖。
1.8
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.0
org.springframework.boot
spring-boot-starter-freemarker
com.entor
ojdbc
11.2.0
com.mchange
c3p0
0.9.5.2
junit
junit
4.12
org.springframework.boot
spring-boot-starter-test
第三步:把Oracle驱动包发布到本地仓库
如果要把本地jar包安装到本地的Maven仓库,可以使用mvn install命令。
例如:
mvn install:install-file -Dfile=C:\app\zhongliwen\product\11.2.0\dbhome_1\jdbc\lib\ojdbc6.jar
-DgroupId=com.entor
-DartifactId=ojdbc
-Dversion=11.2.0 -Dpackaging=jar
第四步:创建Maven子模块
maven-erp-entity:保存实体类的子模块
maven-erp-dao:保存映射接口和映射文件的子模块
maven-erp-business:保存业务组件的子模块
maven-erp-web:保存控制器、视图页面等等的子模块
一共需要建立4个子模块:
erp_entity –> 存放实体包
erp_dao -> 存放数据访问接口及实现类
erp_business -> 存放业务逻辑层接口及实现类
erp_web -> 存放action类代码和前端代码 (此模块的packaging选择war)
Maven子模块之间的依赖关系如下所示:
erp_dao 依赖erp_entity
erp_business 依赖erp_dao
erp_web依赖erp_business
最后在erp_parent父模块把其他4个子模块组合在一起。
erp_entity
erp_dao
erp_business
erp_web
erp_service
第五步:在各模块中创建包
第六步:添加easyui到erp_web工程
将“资料/工具/easyui文件夹”拷贝到erp_web工程的src/main/resources/static目录下。
第七步:添加application文件
在erp_parent工程的src/main/resources目录下新建application.properties文件。然后添加以下内容:
spring.datasource.c3p0.driverClass=oracle.jdbc.OracleDriver
spring.datasource.c3p0.jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl
spring.datasource.c3p0.user=scott
spring.datasource.c3p0.password=tiger
spring.datasource.c3p0.maxPoolSize=100
spring.datasource.c3p0.minPoolSize=10
spring.datasource.c3p0.initialPoolSize=10
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.mvc.static-path-pattern=/static/**
logging.level.root=DEBUG
第八步:配置C3P0数据源
在erp_web工程的com.entor.erp.bootstrap包下,新建MyBatis配置类,然后加入以下内容。
@Configuration // 定义配置信息类
public class DataSourceConfiguration {
/** 定义创建数据源方法 */
@Bean // 定义Bean
@Primary // 主要的候选者
@ConfigurationProperties(prefix="spring.datasource.c3p0") // 配置属性
public DataSource getDataSource(){
return DataSourceBuilder.create() // 创建数据源构建对象
.type(ComboPooledDataSource.class) // 设置数据源类型
.build(); // 构建数据源对象
}
}
第九步:创建SpringBoot启动类
在erp_web工程中的src/main/java下,新建com.entor.erp.controller.Application类。
/*
SpringBoot启动类
*/
@SpringBootApplication(scanBasePackages={“com.entor”})
@MapperScan(basePackages={“com.entor.erp.mapper”})
public class Application {
public static void main(String[] args) {
SpringApplication springApplication
= new SpringApplication(Application.class);
springApplication.run(args);
}
}
2.2 可能遇到的问题
2.2.1 处理红叉(根据实际情况设置)
查看错误原因:
提示不能改变动态web模块的版本到2.3。
解决办法:
打开erp_web工程下的.setting 中的org.eclipse.wst.common.project.facet.core.xml。
将配置中的2.5改成2.3。然后再次更新maven工程即可去掉红叉。
2.3 导入数据库
打开“资料/数据库/建表语句.txt”,把里面的sql命令复制到Oracle数据库中执行。
三、【部门管理】实现列表查询
实现部门列表的查询,最终效果如下:
3.1 前端代码
第一步:创建模版文件
首先,在src/main/resources/templates目录下,创建commons.ftl模版文件,然后把以下内容拷贝到该文件中。
然后,在该目录下创建dep目录,然后在dep目录下新建list.ftl模版文件。
第二步:创建表格
1)定义一个table标签。
2)初始化表格。
url :请求服务器的资源地址。表格需要接收服务器返回的JSON数组格式的字符串。其格式如下所示:
columns :列定义;
singleSelect:为true表示单行选中;
列属性:
3.2 后端代码
后端代码的目标是完成控制器,地址栏输入控制器的地址可以看到列表的json。
第一步:编写实体类
在 erp_entity工程中的com.entor.erp.entity包下建立Dep类。
public class Dep {
private Integer uuid;
private String name;
private String tele;
public Integer getUuid() {
return uuid;
}
public void setUuid(Integer uuid) {
this.uuid = uuid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTele() {
return tele;
}
public void setTele(String tele) {
this.tele = tele;
}
@Override
public String toString() {
return "Dep [uuid=" + uuid + ", name=" + name + ", tele=" + tele + "]";
}
}
第二步:编写映射文件
在erp_dao工程com.entor.erp.dao包下创建DepMapper接口。
@Repository
public interface DepMapper {
@Select("select * from dep")
public List findAll();
}
第三步:编写业务逻辑
在erp_business项目的com.entor.erp.business包下创建 IDepBusiness 接口。
public interface IDepBus {
/**
* 查询所有部门
*/
List findAllDeps();
}
然后在com.entor.erp.business.impl包下编写业务实现类。
@Service
public class DepBusImpl implements IDepBus {
@Autowired
private DepMapper mapper;
@Override
public List findAllDeps() {
return mapper.getDeps();
}
}
第四步:编写控制器
在erp_web工程下的com.entor.erp. controller包下创建DepAction类。
@Controller
@RequestMapping("/dep")
public class DepController {
@Autowired
private IDepBus depBus;
@RequestMapping("/list.do")
public void list() {}
@RequestMapping(path="/list.do", produce="application/json;charset=utf-8")
@ResponseBody
public List list() {
return depBus.findAllDeps();
}
}
第五步:测试代码
运行启动类,然后在地址栏输入:http://localhost:8080/dep/list.do。运行效果如下所示:
四、代码优化
4.1 整合TkMyBatis
4.1.1 TkMyBatis是什么
TkMyBatis是一个MyBatis的通用Mapper工具。它提供了一些通用的增删查改方法,从而简化我们实际开发的工作,提供开发效率。
4.1.2 使用步骤
第一步:引入mapper-spring-boot-starter
修改erp_parent工程引入mapper-spring-boot-starter启动器。
tk.mybatis
mapper-spring-boot-starter
1.1.5
第二步:在实体类上使用JPA注解
public class Dep {
@Id
private Integer uuid;
private String name;
private String tele;
}
注意:如果实体类的属性与表字段名不相同,那么就需要使用@Column指定字段名。
第三步:让XxxMapper继承tk.mybatis.mapper.common.Mapper
一旦继承了Mapper接口,那么就拥有了Mapper中的所有方法。
1)查询:
List select(T record):根据实体中的属性执行查询,查询条件使用等号;
T selectByPrimaryKey(Object key):根据主键执行查询;
List selectAll():查询全部结果;
T selectOne(T record):根据实体中的属性执行条件查询,只能够返回一个结果;
int selectCount(T record):根据实体中的属性按条件查询结果总数;
List selectByExample(Example example):执行高级查询。Example对象用来封装了一些查询条件、排序方式等等。
2)插入
int insert(T record):保存实体,如果属性为Null,那么就保存为Null值;
int insertSelective(T record):保存实体,如果属性为Null,那么就使用数据库的默认值;
3)修改
int updateByPrimaryKey(T record):根据主键更新实体的所有属性,属性值为Null也会更新;
int updateByPrimaryKeySelective(T record):根据主键更新实体的所有属性,属性值为Null 不会更新;
4)删除
int delete(T record):根据实体属性作为条件执行删除;
int deleteByPrimaryKey(Object key):根据主键执行删除;
4.2 整合lombok(自动生成setter和getter方法)
4.2.1 lombok是什么
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。例如:setter、getter、toString方法等等。
官方地址:https://projectlombok.org/
4.2.2 使用步骤
第一步:加入lombok依赖
修改erp_parent工程的pom.xml文件,加入lombok依赖。
org.projectlombok
lombok
1.16.18
provided
第二步:在eclipse根目录下添加lombok-1.16.18.jar
第三步:修改eclipse.ini文件,在文件的最后面加上:-javaagent:lombok-1.16.18.jar。
第四步:在实体类上使用@Data注解接口
@Data
public class Dep {
private Integer uuid;
private String name;
private String tele;
}
五、 【部门管理】查询功能完善
5.1 条件查询
动态组合条件查询。表格上有查询表单,输入部门名称、部门电话进行条件查询,如果同时输入条件则全部进行查询。
5.1.1 实现思路
Controller方法提供一个Dep参数,该参数用来接收表单提交的数据。然后将该对象传递给业务逻辑层和数据访问层处理。
5.1.2 后台实现
实现类中的方法:
@Override
public List findDeps(Dep dep) {
//构造查询条件
Example example = new Example(Dep.class);
Criteria c = example.createCriteria();
if (!StringUtils.isEmpty(dep.getName())) {
c.andLike(“name”, “%” + dep.getName() + “%”);
}
if (!StringUtils.isEmpty(dep.getTele())) {
c.andLike(“tele”, dep.getTele());
}
//设置排序
example.setOrderByClause(“uuid desc”);
return depMapper.selectByExample(example);
}
2. 修改控制器方法
修改控制器的list方法,加入搜索条件参数。
@RequestMapping(path="/list.do", produces=“application/json;charset=utf-8”)
@ResponseBody
public List list(Dep dep) {
return depBus.findDeps(dep);
}
5.1.3 前端页面
然后,在common.ftl模版文件中引入该js文件。
5.1 显示分页栏
使用easyui的datagrid显示表格,可以通过设置“pagination:true”来显示分页栏。
我们要向实现后台的查询,首先需要弄清楚,前端页面在点击页码时向后台传递了什么。我们现在打开谷歌浏览器,F12进入调试模式。点击页码,我们会发现datagrid向后台提交了两个参数 rows page ,从名称的定义上不难理解,page 是页码 rows是每页记录数。
5.2 后台实现
分页的JSON格式:
如果要实现分页功能,那么后台就需要构造这个格式的数据给easyui来展示。
/**
* 统计查询结果
* @param dep 该对象封装了查询条件
* @return
*/
int getTotal(Dep dep);
2)定义Service实现类的方法:
@Override
public List findDeps(Dep dep) {
//构造查询条件
Example example = new Example(Dep.class);
Criteria c = example.createCriteria();
if (!StringUtils.isEmpty(dep.getName())) {
c.andLike(“name”, “%” + dep.getName() + “%”);
}
if (!StringUtils.isEmpty(dep.getTele())) {
c.andLike(“tele”, dep.getTele());
}
//设置排序
example.setOrderByClause(“uuid asc”);
return depMapper.selectByExample(example);
}
@Override
public int getTotal(Dep dep) {
//构造查询条件
Example example = new Example(Dep.class);
Criteria c = example.createCriteria();
if (!StringUtils.isEmpty(dep.getName())) {
c.andLike("name", "%" + dep.getName() + "%");
}
if (!StringUtils.isEmpty(dep.getTele())) {
c.andLike("tele", dep.getTele());
}
return depMapper.selectCountByExample(example);
}
编写控制器方法
@Controller
@RequestMapping("/dep")
public class DepController {
@Autowired
private IDepService depService;
@RequestMapping("/list.do")
public void list() {}
@RequestMapping(path="/getData.do", produces=“application/json;charset=utf-8”)
@ResponseBody
public Map getData(Dep dep, Integer page, Integer rows) {
PageHelper.startPage(page, rows);
List depList = depService.findDeps(dep);
int total = depService.getTotal(dep);
Map map = new HashMap();
map.put(“rows”, depList);
map.put(“total”, total);
return map;
}
}