tags: SSM整合与阅读项目


导入项目

项目是由eclipse来编写的,我使用的开发环境是Idea,那么就需要将eclipse项目导入进去Idea中。要想项目能够启动起来。是这样干的:

导入eclipse的项目

添加对应的Web Model,添加完毕之后,默认会提示要我们创建对应的Facts的。

接着修改Facets中标出的值,因为我们手动创建的话,指向的是Idea中的web目录的。可是项目是用eclipse编写的,因此要改成是WebRoot对应的文件!

接着配置Tomcat,就基本可以让eclipse中的项目在Idea环境下运行了。

  • 当然了、数据库是需要自己配置与eclipse中的环境一模一样的

主菜单跳转JSP页面

在主菜单页面上有很多的URL跳转到不同的JSP页面。

  • 我们的JSP可能是放在WEB-INF下的,是无法直接获取的。因此需要Controller进行转发
  • 如果为每个超链接都写一个Controller方法的话,那么会有点麻烦!

这些超链接是不同的模块下的。但是我们可以使用BaseAction对他们进行统一管理起来

  • 这里使用到了@PathVariable这么一个注解。变量从@RequestMapping中的参数来拿。
  • 所有的主菜单超链接都通过我们的BaseAction来进行处理
//方法参数folder通过@PathVariable指定其值可以从@RequestMapping的{folder}获取,同理file也一样@RequestMapping("/goURL/{folder}/{file}")public String goURL(@PathVariable String folder,@PathVariable String file) {return "forward:/WEB-INF/"+folder+"/"+file+".jsp";}
复制代码

我们常常在跳转页面之前都要查询数据库的数据的,那如果是这样设计的话,我们可以将常用数据放在application域对象中,或者使用ajax来进行获取数据!

分页对象设计

之前我们做的分页对象就仅仅把我们分页所用到的基本属性封装起来。如果页面上有查询条件的话,我们另外创建了一个查询对象

当时候创建出来的查询对象的属性是根据页面上的条件来编写的。这样做得不够好,没有通用性!

这次看见这个项目的Page设计就非常通用了,虽然把查询条件都放在了Page对象中,但我感觉比之前那个好!

  • 由于它使用了easyUI,该组件会自动计算出总页数,所以在Page对象设计的时候就没有对应的总页数属性了。如果我们不是用easyUI的话,我们补上即可!

public class Page<T> implements Serializable {private static final long serialVersionUID = 337297181251071639L;private Integer page;//当前页private Integer rows;//页大小private Integer totalRecord;// 总记录 数private List<T> list;//页面数据列表private String keyWord;//查询关键字private T paramEntity;//多条件查询private Integer start;//需要这里处理//因为它用的是easyUI,所以没有设置总页数的属性,使用Map集合来替代了。private Map<String, Object> pageMap = new HashMap<String, Object>() ;public Map<String, Object> getPageMap() {return pageMap;}/*public void setPageMap(Map<String, Object> pageMap) {this.pageMap = pageMap;}*/public T getParamEntity() {return paramEntity;}public void setParamEntity(T paramEntity) {this.paramEntity = paramEntity;}public Integer getPage() {return page;}public void setPage(Integer page) {this.page = page;}public Integer getRows() {return rows;}public void setRows(Integer rows) {this.rows = rows;}/*public Integer getTotalRecord() {return totalRecord;}*/public void setTotalRecord(Integer totalRecord) {pageMap.put("total", totalRecord);this.totalRecord = totalRecord;}
/*  public List<T> getList() {return list;}*/public void setList(List<T> list) {pageMap.put("rows", list);this.list = list;}public String getKeyWord() {return keyWord;}public void setKeyWord(String keyWord) {this.keyWord = keyWord;}public Integer getStart() {this.start = (page-1)*rows;return start;}public void setStart(Integer start) {this.start = start;}@Overridepublic String toString() {return "Page [page=" + page + ", rows=" + rows + ", totalRecord="+ totalRecord + ", list=" + list + ", keyWord=" + keyWord+ ", paramEntity=" + paramEntity + ", start=" + start + "]";}
}
复制代码
  • 使用了泛型对象的话,我们就可以完成多条件查询了!这个泛型对象就相当于我们的查询对象!

抽取Service层

之前我们也抽取过Service层的代码,当时候也觉得用得十分巧妙:

  • 在baseService中提供一个setBaseDao()的方法
  • 具体serviceImpl使用具体Dao的时候,通过setDao来进行注入对应的Dao对象,同时调用父类的setDao方法,让BaseService的BaseDao能够实现实例化!

然而,这次看到的baseService就用得更加巧妙了,并且设计得更加好!

如下代码:

package cn.itcast.scm.service.impl;import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;import javax.annotation.PostConstruct;import org.springframework.beans.factory.annotation.Autowired;import cn.itcast.scm.dao.AccountMapper;
import cn.itcast.scm.dao.AccountRecordsMapper;
import cn.itcast.scm.dao.BaseMapper;
import cn.itcast.scm.dao.BuyOrderDetailMapper;
import cn.itcast.scm.dao.BuyOrderMapper;
import cn.itcast.scm.dao.GoodsMapper;
import cn.itcast.scm.dao.SupplierMapper;
import cn.itcast.scm.dao.SysParamMapper;
import cn.itcast.scm.entity.Page;
import cn.itcast.scm.service.BaseService;public class BaseServiceImpl<T> implements BaseService<T> {protected  BaseMapper<T> baseMapper;@Autowiredprotected  SupplierMapper supplierMapper;@Autowiredprotected  AccountMapper accountMapper;@Autowiredprotected  GoodsMapper goodsMapper;@Autowiredprotected  BuyOrderMapper buyOrderMapper;@Autowiredprotected  BuyOrderDetailMapper buyOrderDetailMapper;@Autowiredprotected  AccountRecordsMapper accountRecordsMapper;@Autowiredprotected  SysParamMapper sysParamMapper;@PostConstruct//在构造方法后,初化前执行private void initBaseMapper() throws Exception{//完成以下逻辑,需要对研发本身进行命名与使用规范//this关键字指对象本身,这里指的是调用此方法的实现类(子类)System.out.println("=======this :"+this);System.out.println("=======父类基本信息:"+this.getClass().getSuperclass());System.out.println("=======父类和泛型的信息:"+this.getClass().getGenericSuperclass());ParameterizedType type =(ParameterizedType) this.getClass().getGenericSuperclass();//获取第一个参数的classClass clazz = (Class)type.getActualTypeArguments()[0];System.out.println("=======class:"+clazz);//转化为属性名(相关的Mapper子类的引用名)Supplier  supplierMapperString localField = clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1)+"Mapper";System.out.println("=======localField:"+localField);//getDeclaredField:可以使用于包括私有、默认、受保护、公共字段,但不包括继承的字段Field field=this.getClass().getSuperclass().getDeclaredField(localField);System.out.println("=======field:"+field);System.out.println("=======field对应的对象:"+field.get(this));Field baseField = this.getClass().getSuperclass().getDeclaredField("baseMapper");System.out.println("=======baseField:"+baseField);System.out.println("=======baseField对应的对象:"+baseField.get(this));//field.get(this)获取当前this的field字段的值。例如:Supplier对象中,baseMapper所指向的对象为其子类型SupplierMapper对象,子类型对象已被spring实例化于容器中baseField.set(this, field.get(this));System.out.println("========baseField对应的对象:"+baseMapper);} }复制代码

这个baseService并没有给出对应的setDao的方法,那它是怎么将BaseDao实例化的呢???关键就在于initBaseMapper()这个方法!

我们来看一下方法内部打印数据的内容吧:

=======this :cn.itcast.scm.service.impl.BuyOrderServiceImpl@13a739e
=======父类基本信息:class cn.itcast.scm.service.impl.BaseServiceImpl
=======父类和泛型的信息:cn.itcast.scm.service.impl.BaseServiceImpl<cn.itcast.scm.entity.BuyOrder>
=======class:class cn.itcast.scm.entity.BuyOrder
=======localField:buyOrderMapper=======field:protected cn.itcast.scm.dao.BuyOrderMapper cn.itcast.scm.service.impl.BaseServiceImpl.buyOrderMapper
=======field对应的对象:org.apache.ibatis.binding.MapperProxy@7cc946
=======baseField:protected cn.itcast.scm.dao.BaseMapper cn.itcast.scm.service.impl.BaseServiceImpl.baseMapper
=======baseField对应的对象:null
========baseField对应的对象:org.apache.ibatis.binding.MapperProxy@7cc946
复制代码

这个方法被@PostConstruct注解给修饰着

  • 于是这个方法的执行是在Servlet构造函数之后、Servlet的init()方法之前被执行!

通过我一阵的梳理,BaseDao的实例化过程是这样的:

  • 我们具体的ServiceImpl被Spring所管理着,当具体serviceImpl被Spring实例化时,会自动调用其父类也就是baseServiceImpl
  • 当发现父类baseServiceImpl有@PostConstruct注解给修饰,于是就调用initBaseMapper()
  • 这个方法首先是获取泛型的信息(例如:BuyOrder)
  • 将泛型的信息与Mapper字符串进行拼接,拼接成(BuyOrderMapper)
  • 通过反射获取baseServiceImpl的成员变量buyOrderMapper--->这个是Mapper代理的对象,从上面的输出对象就可以看出来。
  • 然后也通过反射将baseMapper进行实例化。

其实上面也是通过具体的serviceImpl来对baseDao来进行初始化,不过它这样子做的话就显得更加优雅了。并不需要在每个具体的serviceImpl使用setDao()的方式来进行实例化。

通过上面的解释、我们把注释写上,就很容易理解了。

/*** 每当service实例化的时候,这个方法都会被调用* @throws Exception*/@PostConstructprivate void initBaseMapper() throws Exception{//获取泛型的信息ParameterizedType type =(ParameterizedType) this.getClass().getGenericSuperclass();Class clazz = (Class)type.getActualTypeArguments()[0];//拼接成“泛型”Mapper字符串String localField = clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1)+"Mapper";//通过反射来获取成员变量的值Field field=this.getClass().getSuperclass().getDeclaredField(localField);Field baseField = this.getClass().getSuperclass().getDeclaredField("baseMapper");//将baseDao来进行实例化baseField.set(this, field.get(this));}复制代码

分析项目的业务

本项目主要用EASY-UI来作为前段的页面构建。这里就不一一去探究EASY-UI的用法的,当用到这个前段UI的时候再回头看吧。下面就直接分析它的具体逻辑体悟了。

用户登陆

首先,程序的入口是用户登录的界面。用户设计得比较简单,因为只用来做登录。

CREATE TABLE account
(acc_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,acc_login VARCHAR(20),acc_name VARCHAR(20),acc_pass VARCHAR(20)
);复制代码

对于用户登陆而言,我们已经是非常熟悉这个业务了。只是在数据库中对比一下数据、如果存在这个数据,那么在session域中保存即可!

基本数据的数据库表


CREATE TABLE supplier
(sup_id INT(11) PRIMARY KEY NOT NULL,sup_name VARCHAR(20),sup_linkman VARCHAR(20),sup_phone VARCHAR(11),sup_address VARCHAR(100),sup_remark VARCHAR(100),sup_pay DECIMAL(12,2),sup_type VARCHAR(10)
);
复制代码
CREATE TABLE goods
(goods_Id VARCHAR(36) PRIMARY KEY NOT NULL,goods_name VARCHAR(20),goods_unit VARCHAR(10),goods_type VARCHAR(10),goods_color VARCHAR(10),goods_store INT(11),goods_limit INT(11),goods_commission DECIMAL(2,2),goods_producer VARCHAR(50),goods_remark VARCHAR(100),goods_sel_price DECIMAL(12,2),goods_buy_price DECIMAL(12,2)
);
复制代码
CREATE TABLE store_house
(sh_id VARCHAR(10) PRIMARY KEY NOT NULL,sh_name VARCHAR(20),sh_responsible VARCHAR(20),sh_phone VARCHAR(11),sh_address VARCHAR(50),sh_type VARCHAR(10),sh_remark VARCHAR(100)
);复制代码

上边这几张表都仅仅是CRUD的操作。

  • 上面已经说了,我们的URL都交由了baseAction来进行处理。但是我们需要增加、查询的时候可能是需要数据库中查询出来的数据的。当然了,有些是可以通过easy-UI部分的控件能从数据库中获取得到【分页数据】,可是有的地方还是需要我们手动去查询出来。

那么这个项目是这样处理的,将经常用到的数据用一张表保存起来

drop table if exists sys_param;
/*====================================系统参数表==============================*/
/*==============================================================*/
/* Table: sys_param                                             */
/*==============================================================*/
/*
create table sys_param
(sys_param_id         bigint  auto_increment,sys_param_field      varchar(50),sys_param_value      varchar(50),sys_param_text       varchar(50),primary key (sys_param_id)
);
*/
create table sys_param
(sys_param_id         bigint  auto_increment,sys_param_field      varchar(50),sys_param_value      varchar(500),sys_param_text       varchar(50),sys_param_type       varchar(2),   primary key (sys_param_id)
);
insert into sys_param(sys_param_field,sys_param_value,sys_param_type) values('shId','select s.sh_id as sys_param_value,s.sh_name as sys_param_text from store_house s','1');insert into sys_param(sys_param_field,sys_param_value,sys_param_text) values('supType','1','一级供应商');
insert into sys_param(sys_param_field,sys_param_value,sys_param_text) values('supType','2','二级供应商');
insert into sys_param(sys_param_field,sys_param_value,sys_param_text) values('supType','3','普通供应商');
insert into sys_param(sys_param_field,sys_param_value,sys_param_text) values('goodsColor','1','红色');
insert into sys_param(sys_param_field,sys_param_value,sys_param_text) values('goodsColor','2','绿色');
insert into sys_param(sys_param_field,sys_param_value,sys_param_text) values('goodsColor','3','蓝色');
select * from sys_param;复制代码

上面我们可以看到,除了单单保存了一些的基本属性之外,我们来存储了SQL语句,那么我们怎么将SQL语句转成是我们的数据呢???

  • 上面就是查询仓库的地址。也就是说,当页面加载的时候,我们的地址就被查询出来了。

那它是怎么实现这种玩意的呢??

Mapper查询表的数据

<select id="selectList" parameterType="String" resultMap="sysParamResultMap">      select * from sys_param</select><!-- 查询其它表的数据,使用${value}格式,允许使用sql语句作为参数执行 --><select id="selectOthreTable" parameterType="string" resultMap="sysParamResultMap">${value}</select>
复制代码

Service将数据封装到一个总的Map中。具体的做法是这样子的:


package cn.itcast.scm.service.impl;import cn.itcast.scm.entity.SysParam;
import cn.itcast.scm.service.SysParamService;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service("sysParamService")
public class SysParamServiceImpl extends BaseServiceImpl<SysParam> implements SysParamService {@Overridepublic Map<String, Object> selectList() {//查询出表中所有所有数据List<SysParam> sysParams = sysParamMapper.selectList("");//存储属性字段具体的值Map<String, Object> fieldMap = null;//最终的Map,key是属性字段,value是一个map(属性字段具体的值)Map<String, Object> sysParamMap = new HashMap<String, Object>();//遍历表中的记录,看是否有类型为1的字段数据!也就是SQL数据for (SysParam sysParam : sysParams) {if ("1".equals(sysParam.getSysParamType())) {String sql = sysParam.getSysParamValue();//执行SQL,得到查询后的记录List<SysParam> otherList = sysParamMapper.selectOthreTable(sql);fieldMap = new HashMap<>();/*** select s.sh_id as sys_param_value,s.sh_name as sys_param_text  from store_house s*///遍历查询后的记录,并把数据存到字段MAPfor (SysParam otherSysParam : otherList) {/*** key = 仓库的具体Id* value = 页面显示的仓库名称*/fieldMap.put(otherSysParam.getSysParamValue(), otherSysParam.getSysParamText());}/*** key = shId* value = 存储具体数据的Map集合*/sysParamMap.put(sysParam.getSysParamField(), fieldMap);} else {//判断系统参数的map中是否存在字段的map,如果不存在,就新建一个if (sysParamMap.get(sysParam.getSysParamField()) == null) {fieldMap = new HashMap<>();/*** key  = 1* value = 一级供应商*/fieldMap.put(sysParam.getSysParamValue(), sysParam.getSysParamText());/*** key = supType* value = 存储具体数据的Map集合*/sysParamMap.put(sysParam.getSysParamField(), fieldMap);} else {//如果存在,那么就在原先的Map集合中添加fieldMap = (Map<String, Object>) sysParamMap.get(sysParam.getSysParamField());fieldMap.put(sysParam.getSysParamValue(), sysParam.getSysParamText());}}}/*** key = shId        value = Map-->(1  主仓库)*                             (2  分仓库)** key = supType    value= Map-->( 1   一级供应商)*                              ( 2  二级供应商)...* key = goodsColor  value = Map--> (1  红色)....*/return sysParamMap;}
}
复制代码

controller使用@PostConstruct注解,在初始化的时候就把数据加载到application域对象中

//系统启动时加载参数@PostConstructpublic void initSysParam(){loadSysParam();}//用来加载系统参数   public void loadSysParam(){Map<String, Object> sysParamMap = sysParamService.selectList();application.setAttribute("sysParam", sysParamMap);System.out.println("===================系统参数加载成功2=====================");}复制代码

如果您觉得这篇文章帮助到了您,可以给作者一点鼓励

阅读SSM项目之scm【第一篇】相关推荐

  1. 海外多语言商城源码项目开发搭建 第一篇

    前一段时间开发了一套关于海外多语言商城源码项目,现在整理发出来,给大家参考和学习. 程序采用主流的框架:ThinkPHP 数据库采用的是:MySQL 支持语言:中文,英文,西班牙语,葡萄牙语等 程序开 ...

  2. 闲云旅游项目开发-(第一篇:使用Element-ui实现主页轮播图)

    业务需求: 初始化布局 页头页脚公共组件 首页轮播图 一 初始化默认全局布局 nuxtjs 提供了一个公共组件 layouts/default.vue,相当于以前的 app.vue .该布局组件默认作 ...

  3. SSM项目--资产管理系统

    ssm项目--资产管理系统 这篇博客是上一篇SSH的姊妹篇,同一个项目的不同实现框架,可以比对一下,比较SSH和SSM的整合的异同和流程. 目录 说明 项目的结构 配置web.xml 配置spring ...

  4. 编程书籍阅读随谈(第一篇)

    做.NET程序员也有几年了,从在大学到现在读过的编程书也的确有不少,读过.NET.Java.Python.Node.JS.底层原理等等的书籍.不知道自己学习的怎么样,但是也的确去学习过这些东西. (备 ...

  5. b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释

    b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释 继续上篇,上篇里忘记了也很重要的前端部分,今天的网站基本上是以一个启示页,然后少量的整页切换,大量的浏览器后台调用web服务局部.动态更 ...

  6. .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

    写在前面 千呼万唤始出来,首先,请允许我长吸一口气!真没想到一份来自28岁老程序员的自白 这篇文章会这么火,更没想到的是张善友队长的公众号居然也转载了这篇文章,这就导致两天的时间就有两百多位读者朋友加 ...

  7. idea搭建SSM项目这一篇就够了

    目录 1. 创建Maven项目 1.1 创建一个新的项目  (请先连接好网络) 1.2 选择maven --> 选择你的jdk版本 --> 勾选Create from archetype ...

  8. 微信小程序商城项目实战(第一篇:项目搭建与首页)

    商城项目第一篇 项目搭建 项目结构 编写整个项目中需要用到的功能 request.js 全局样式 组件(搜索框) 首页 代码编写 效果图 项目搭建 后端接口:https://www.showdoc.c ...

  9. Vue项目实战 —— 后台管理系统( pc端 ) 第一篇

    前期回顾     我只写注释 -- 让Ai写代码_0.活在风浪里的博客-CSDN博客前期回顾 Vue项目实战 -- 哔哩哔哩移动端开发-- 第二篇_0.活在风浪里的博客-CSDN博客https://b ...

最新文章

  1. java 模拟登陆web系统_关于java模拟登陆WEB的问题。
  2. 云栖社区 测试技术社区大群 正式成立!还在等什么,快来加入我们...
  3. springboot 控制台输出错误信息_springboot日志详解
  4. Swing俄罗斯游戏编写详解(附源码)
  5. 工业相机与镜头分辨率匹配
  6. qt鼠标进入窗体后,窗体自动置顶
  7. mysql5.6 pid_MySQL5.6启动报错The server quit without updating PID file
  8. 东部分布式光伏迎来发展高潮
  9. java textarea 自动滚动条,textarea根据内容自动延伸,不显示滚动条
  10. matlab怎么新建文件运行不了,关于:Matlab中直接双击fig文件运行出错,而从.m文件运行却不会出错问题的一点心得...
  11. 人机交互选择判断练习题
  12. Nginx解决无法代理域名问题
  13. CG CTF RE Py交易
  14. 【优化模型】求线性齐次方程组的通解
  15. 【Unity】Jay 开发日志(四)——道具效果的实现(下)
  16. 怎么调用计算机cad,CAD电脑版怎么使用教程
  17. 一文讲透hdfs的delegation token
  18. C++ explicit的使用
  19. python sqlachemy模糊查询报错
  20. 计算机四级维修工查询,计算机安装调试维修员(四级)技能鉴定试题单总汇.doc

热门文章

  1. 安卓编译php,编译PHP
  2. sqlserver 如何把一列分为一行显示_EXCEL神乎其技 多列追加为一列
  3. wxpython使用多进程_wxPython 使用总结
  4. cups支持的打印机列表_在Mac上怎样更新打印机软件?
  5. 使用useEffect常见问题!
  6. MySQL聚集索引详解_MySQL innodb 聚集索引的概念与使用教程
  7. mysql 动态加载数据库数据库连接,如何根据每个客户端动态连接mysql数据库?
  8. java 如何添加背景音乐_Java程序怎样添加背景音乐?
  9. python中如何计算集合的长度_Python如何计算序列长度 python dataframe中元素如何统计?...
  10. 后副车架焊接机器人_焊接机器人的工装设计和工装的使用方法