让ERP的服务更开放! ——用微服务架构搭建的一套基于EBS的API服务系统

1. 源码下载地址

源码连接: https://github.com/samt007/xygerp-api-demohtml

这是用Spring Cloud微服务架构搭建的一套基于EBS的API服务系统前端

如对本文有任何的疑问,请联系我:samt007@qq.comjava

2. Introduction介绍

这是一篇传统ERP系统和基于Java的微服务架构有效结合的技术文档。git

传统ERP关注的是企业内部的信息化管理。当ERP系统能将其服务发布出去以后(结合微服务架构),就能够很好实现与第三方系统的无缝对接,同时也能够实现扩展ERP自己的功能。 目标是:让ERP的服务更开放!github

2.1 它有什么用?

简单来讲,就是:web

至关于作一个中间服务平台,把ERP的API作成Web Service与其它系统集成。docker

下面具体说明它的做用。数据库

1. 若是没有它...

若是没有一个统一的API对接平台,那么ERP和第三方系统作对接,那会是下图所示的结构: 后端

这里写图片描述

从上图能够看出,各个第三方系统分别和ERP作对接,不管是DBLINK仍是经过本身的Web Service, 都是杂乱的,没能统一管理的。简单来讲就是各自为政,为对接而须要作的事情都是零碎的。api

当第三方系统愈来愈多的时候,那对于平常的运维将会是一个灾难的问题。举个例子,就一个简单的运维:密码修改,须要调整的地方就会不少,也很容易遗漏。

特别指出的是,接口功能的复用方面也是个难题。假设一个查询库存的接口,CRM系统和在线下单系统均可以用的,须要开发2次。

2. 自从有了它...

有了这套统一的API系统以后,ERP系统和别的系统之间的对接就变成了这个结构:

这里写图片描述

因此,有了它,至关于ERP的API均可以经过这服务平台给开发出去,基本上全部的接口能够完成的业务,均可以经过这套服务平台来完成。

能够实现:

  • 对外服务的统一
  • API服务之间能够实现互相调用,而且实现服务取数和处理的逻辑的统一
  • 代码的统一,提升开发效率。特别是comm代码的部分。
  • 提升与第三方系统对接的稳定性:只须要关注该微服务系统的运行稳定性便可。

3. 有哪些实例?

举个例子:

1) 成品进出条码管理系统:

大概这个需求: 成品入库的时候,直接能够用条码枪扫条码或者二维码就能够入库;销售出库的时候,也能够经过刷成品的条码直接进行出库。JIT管理。

经过这个系统的实现逻辑是: 经过EBS的用户名和密码能够登入条码枪上的APP系统。而后,刷条码的时候,经过该Web Service能够产生对应的事务处理!例如完工入库,处理物料搬运单等。

下面是该系统的一些截图

注意:该功能后台API由该微服务提供,前台是安卓的APP

这里写图片描述

2) 与各个第三方系统的集成:

每一个企业内部都有各类第三方系统,这些系统或多或少都须要和EBS进行集成。传统的集成方法是经过DBLINK。

可是有这套Web Service系统以后,就能够统一经过该Web Service做为中介,和EBS进行数据的集成交互!

2.2 什么是微服务?

关于它的解析,网上资料不少。 这里引用某位大神的总结(引用:http://blog.51cto.com/ityouknow/1974080),解析得比较到位:

微服务的概念源于2014年3月Martin Fowler所写的一篇文章“Microservices”。

微服务架构是一种架构模式,它提倡将单一应用程序划分红一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每一个服务运行在其独立的进程中,服务与服务间采用轻量级的通讯机制互相沟通(一般是基于HTTP的RESTful API)。每一个服务都围绕着具体业务进行构建,而且可以被独立地部署到生产环境、类生产环境等。另外,应尽可能避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每一个微服务仅关注于完成一件任务并很好地完成该任务。在全部状况下,每一个任务表明着一个小的业务能力。

微服务架构优点

复杂度可控:在将应用分解的同时,规避了本来复杂度无止境的积累。每个微服务专一于单一功能,并经过定义良好的接口清晰表述服务边界。因为体积小、复杂度低,每一个微服务可由一个小规模开发团队彻底掌控,易于保持高可维护性和开发效率。

独立部署:因为微服务具有独立的运行进程,因此每一个微服务也能够独立部署。当某个微服务发生变动时无需编译、部署整个应用。由微服务组成的应用至关于具有一系列可并行的发布流程,使得发布更加高效,同时下降对生产环境所形成的风险,最终缩短应用交付周期。

技术选型灵活:微服务架构下,技术选型是去中心化的。每一个团队能够根据自身服务的需求和行业发展的现状,自由选择最适合的技术栈。因为每一个微服务相对简单,故须要对技术栈进行升级时所面临的风险就较低,甚至彻底重构一个微服务也是可行的。

容错:当某一组建发生故障时,在单一进程的传统架构下,故障颇有可能在进程内扩散,造成应用全局性的不可用。在微服务架构下,故障会被隔离在单个服务中。若设计良好,其余服务可经过重试、平稳退化等机制实现应用层面的容错。

扩展:单块架构应用也能够实现横向扩展,就是将整个应用完整的复制到不一样的节点。当应用的不一样组件在扩展需求上存在差别时,微服务架构便体现出其灵活性,由于每一个服务能够根据实际需求独立进行扩展。

2.3 ERP API微服务系统架构说明

2.3.1 系统开发逻辑说明

从上面的解析得知:微服务是一种技术架构,将一个庞大的服务体系拆分为若干个子服务执行。 问题来了,应该如何拆分呢?就是服务的拆分原则是什么。

这个问题就像是一个大表如何进行分区同样,其实我以为是具体问题具体分析。 因为我开发的是基于EBS的微服务系统,正常来讲,比较合理的划分规则应该是以EBS的模块来分。

至关于每一个模块都划分为一个单独的微服务。例如FND模块,INV模块,WIP模块等等。

有时候,为了某个目的,可能有些功能是定制的,须要提取几个模块的数据来用,并且被别的模块重用的几率很低。因此,实际上也能够以定制的功能来划分微服务。

目前来讲,该系统包括2个子服务:

  • xygerp-ald服务:ald模块

这个是整个微服务API的核心ald模块。这个模块的主要功能是验证用户的登陆,为全部的api模块提供统一的token认证。至关于ebs的FND模块。

  • xygerp-albc服务:albc子模块

这个项目是属于微服务的API模块之一:条码管理系统提供数据以及数据处理的API。 主要是为条形码传输系统用。

固然,将来能够添加若干个服务。微服务架构的优点是有很好的横向扩展能力!

2.3.2 微服务系统架构图

该系统的架构图以下所示。

这里写图片描述

注意:

1.Spring Cloud模块中,实际上Spring Security并非单独的一个模块,而是融入到每个业务微服务模块中! 每一个微服务都必需要有token认证才容许访问API,它很是重要! 因此我将它给列到Spring Cloud模块中。

2.图中有些模块目前尚未实现。 目前实现了架构总体,包括如下的服务(下一个章节会具体说明每一个模块的用途):

xygerp-ald

xygerp-albc

xygerp-server-eureka

xygerp-server-zuul

注意: 之后会按需添加别的模块。

3 系统开发流程

接下来是一步一步来开发一套这个基于Spring Cloud的微服务系统。

3.1 必须掌握的基础开发技术知识点

开发系统都必需要打好基础。因此,这里列出了开发基于Spring Cloud的微服务系统须要掌握的开发技术。

下面我不会具体解说每个开发技术如何学习,由于这并非本文的重点。工欲善其事必先利其器,基础仍是必需要打好。

1)Java语言

必需要熟悉java,不然基本不用看文档了。先打好基础吧!

2)Maven项目管理工具

系统开发的项目都是以maven作项目管理的,因此必需要先安装并掌握maven工具。

3)Oracle数据库+PLSQL+SQL语言

数据库端的开发技术。这里选用Oracle数据库,由于EBS就是基于Oracle数据库的ERP系统。

3.2 须要熟悉的java框架

Java技术发展到如今,已经出现了许多很是优秀的开源框架,咱们能够借助这些框架来快速开发系统。

3.2.1 Spring框架技术栈(全家桶)

Spring是目前开源的主流的技术包。 该系统主要用到的技术栈是:Spring boot,Spring Security以及Spring Cloud。

  1. Spring Boot

系统基于SpringBoot快速开发。选择目前热度很高的SpringBoot,最大限度地下降配置复杂度,把大量的精力投入到业务开发中来。

  1. Spring MVC

利用Spring MVC框架处理全部的url请求,简单易用。

  1. Spring Security

Spring security是一个强大的和高度可定制的身份验证和访问控制框架。它是确保基于Spring的应用程序的标准。 这里主要是用Spring Security框架处理Token机制。

  1. Spring Cloud

Spring Cloud是一系列框架的有序集合。 它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,均可以用Spring Boot的开发风格作到一键启动和部署。 注意:本系统目前使用Spring Cloud的2个模块

  • 请求统一经过API网关(Zuul)来访问内部服务.
  • 网关接收到请求后,从注册中心(Eureka)获取可用服务

3.2.2 MyBatis

ORM框架选用MyBatis。

主要是考虑到它可以很好支持SQL语句:MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。 另外,还用到了MyBatis的一些提升开发效率的插件,特别是通用Mapper和PageHelper分页插件!

3.2.3 Alibaba druid

DRUID是阿里巴巴开源平台上一个数据库链接池实现。它结合了C3P0、DBCP、PROXOOL等DB池的优势,同时加入了日志监控,能够很好的监控DB池链接和SQL的执行状况。

3.2.4 Swagger

前端和后端的惟一联系,变成了API接口。

API文档变成了先后端开发人员联系的纽带,变得愈来愈重要,swagger就是一款让你更好的书写API文档的框架。

3.3 须要准备的软件工具

3.3.1Redis

目前用Redis的主要做用是存取token,以配合实现Spring Security完成api访问的安全机制。

之后能够考虑作缓存或者消息队列等高级功能。

3.3.2Docker

基于Docker的容器化部署。

因为使用了微服务架构后,咱们的系统将会由不少子系统构成。 为了达到多个系统之间环境隔离的目的,咱们能够将它们部署在多台服务器上,可这样的成本会比较高,并且每台服务器的性能可能都没有充分利用起来。

因此咱们很天然地想到了虚拟机,在同一台服务器上运行多个虚拟机,从而实现环境的隔离,每一个虚拟机上运行独立的服务。

然而虚拟机的隔离成本依旧很高,由于它须要占用服务器较多的硬件资源和软件资源。 因此,在微服务结构下,要实现服务环境的隔离,Docker是最佳选择。它比虚拟机更加轻量级,占用资源较少,并且可以实现快速部署。

备注:后面有专题说明这个工具如何安装使用。因为篇幅缘由,本文档暂时不讲解容器化部署。

3.3.3 Jenkins

Jenkins自动化构建工具。

当咱们采用了微服务架构后,咱们会发现这样一个问题。整个系统由许许多多的服务构成,这些服务都须要运行在单独的容器中,那么每次发布的复杂度将很是高。

首先你要搞清楚这些服务之间的依赖关系、启动的前后顺序,而后再将多个子系统挨个编译、打包、发布。这些操做技术难度低,却又容易出错。

那么有什么工具可以帮助咱们解决这些问题呢?答案就是——Jenkins。

它是一款自动化构建的工具,简单的来讲,就是咱们只须要在它的界面上按一个按钮,就能够实现上述一系列复杂的过程。

备注:后面有专题说明这个工具如何安装使用。因为篇幅缘由,本文档暂时不讲解自动化构建。

3.4 具体开发流程

如今开始手把手来搭建一套这样子的系统。

3.4.1 建立Maven项目的组织结构

先建立一个微服务系统的父级项目:xygerp-api

再在这个项目下面分别建立下面几个子项目:

项目名称 说明
xygerp-ald ald模块,端口:8180。这个是整个微服务API的核心ald模块。这个模块的主要功能是验证用户的登陆,为全部的api模块提供统一的token认证。至关于ebs的FND模块。
xygerp-albc albc子模块,端口:8181。这个项目是属于微服务的API模块之一:条码管理系统提供数据以及数据处理的API。主要是为条形码传输系统用。
xygerp-comm comm模块这个项目是全部API项目的核心依赖项目。说白了就是将API微服务架构的全部项目的公用代码能够抽取在这里。
xygerp-basic-support 核心基础支撑模块这个项目是全部API项目的基础数据支撑项目。这里统一归集了全部的Entity!由于对于Entity来讲,应该是整个微服务都公用的。
xygerp-server-eureka Spring Cloud的服务与发现的服务中心。端口:8101。这个模块是Spring cloud的最核心的模块了,用来处理各个微服务之间的服务调用的。
xygerp-server-zuul Spring Cloud服务网关。端口:8102。在Spring Cloud架构体系内的全部微服务都经过Zuul来对外提供统一的访问入口,全部须要和微服务架构内部服务进行通信的请求都走统一网关。

它们的目录结果是这样子的:

这里写图片描述

注意: 关于xygerp-basic-support:核心基础支撑模块

可能您会有疑问:为何不将entity归并在它所属的模块?实际上是这样的,我主要是考虑到服务之间的互相调用的问题。

微服务虽然客观上是一个单独的服务,可是,实际上大部分的功能确定是互相调用的。举个例子,销售订单模块调用库存模块的功能查询个库存是很正常的业务吧?

若是entity不共用的话,至关于销售模块获得的库存模块的结果没法归集为bean来处理,这样子对于后台的处理会带来极大的不便!

3.4.2 构建模块的依赖关系

接着须要经过pom文件来指定它们之间的依赖关系,依赖关系以下图所示。

1. 业务服务部分:

这里写图片描述
注意,上面的4个项目是有依赖关系的。 因此,xygerp-ald和xygerp-albc部署方式 改成war部署 (主要是为了利用jenkins进行自动化部署)。

而xygerp-comm和xygerp-basic-support只是为各个微服务提供基础代码支撑,因此是jar部署便可。

此外,为了简化各个模块的配置,咱们将全部模块的通用依赖放在Project的pom文件中,而后让全部模块做为Project的子模块。 这样子模块就能够从父模块中继承全部的依赖,而不须要本身再配置了。

在父pom中指定子模块

modules标签指定了当前模块的子模块是谁,可是仅在父模块的pom文件中指定子模块还不够,还须要在子模块的pom文件中指定父模块是谁。

<modules>
        <module>xygerp-comm</module>          <!--核心Comm模块 -->
        <module>xygerp-basic-support</module>    <!--核心基础支撑模块 -->
        <module>xygerp-server-eureka</module>   <!--Eureka服务治理模块 -->
        <module>xygerp-server-zuul</module>      <!--zuul动态路由模块 -->
        <module>xygerp-ald</module>             <!--核心ald模块 -->
        <module>xygerp-albc</module>           <!--子模块:albc模块,提供条码对接API服务 -->
    </modules>

复制代码

须要在子模块中指定父模块

<parent>
        <artifactId>xygerp</artifactId>
        <groupId>com.xygerp</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
</parent>

复制代码

备注:具体代码直接看源码吧。这里只是说起了一些重点设置而已。

因此,到此为止,模块的依赖关系配置完毕!但要注意模块打包的顺序。

因为全部模块都依赖于xygerp-comm模块和xygerp-basic-support模块,所以在构建模块时,首先须要编译、打包、安装xygerp-comm模块和xygerp-basic-support模块,将它打包进本地仓库中,这样上层模块才能引用到。当该模块安装完毕后,再构建上层模块。 不然在构建上层模块的时候会出现找不到xygerp-comm模块中类库的问题。

Tips: 其实,若是是在父级目录直接用mvn package总体打包的话,那打包构建的顺序在父pom中是直接指定了!

2. 微服务架构服务治理部分

xygerp-server-eureka:Spring Cloud服务注册和发现。就是处理服务之间的治理。

xygerp-server-zuul:Spring Cloud的统一API网关服务。

Tips: 这2个项目是为了实现微服务架构而用到的核心服务。因此,它们是相对独立的。不须要依赖父pom。

3.4.3用mvn编译命令打包代码

上面的项目都创建好以后,再添加全部项目都须要用到的依赖(具体代码能够参考个人源码)。

都没问题的话,就能够用mvn命令进行打包项目了:

mvn clean install -Dmaven.test.skip=true -P dev

这里简单解析一下指令:

mvn:Maven的统一指令。

clean install:表示要构建该项目。

-Dmaven.test.skip=true:表示构建的时候要跳过测试模块。

-P dev:表示构建的时候,启用 dev 的Spring boot参数运行系统。

若是一切都OK,那正常的结果以下:

这里写图片描述

3.5 本地电脑测试系统

代码搞定了,接下来须要考虑的事情应该是如何测试。 毕竟全部的系统都必需要通过测试,特别是这种配置多,涉及范围广的系统。

这个就不得不说一下Spring boot的优点了。Spring boot的打包应用默认内置了tomcat服务。 换句话说,只须要java命令执行一下Spring boot打包的target结果,就能够启动一个tomcat服务啦!真挺方便测试的!

3.5.1 启动本地系统的服务

假设个人xygerp-api项目在这里:D:\JSP_MyEclipse\xygerp-api

而后分别打开4个cmd命令窗口,执行:

D:\JSP_MyEclipse\xygerp-api\xygerp-server-eureka\target>java -jar xygerp-server-eureka-1.0-SNAPSHOT.war
D:\JSP_MyEclipse\xygerp-api\xygerp-server-zuul\target>java -jar xygerp-server-zuul-1.0-SNAPSHOT.war
D:\JSP_MyEclipse\xygerp-api\xygerp-ald\target>java -jar xygerp-ald-1.0-SNAPSHOT.war
D:\JSP_MyEclipse\xygerp-api\xygerp-albc\target>java -jar xygerp-albc-1.0-SNAPSHOT.war

复制代码

以下图:

这里写图片描述

3.5.2 本地测试API服务系统

本地测试环境的服务启动起来了,接着就是进行具体的数据测试。

首先测试Eureka的服务注册以及发现,确认服务是否都已经注册到系统中:

这里写图片描述

而后,用swagger测试用户登陆的功能: http://127.0.0.1:8102/xygerp/ald/swagger-ui.html 目前是测试是否能够正常产生token。

这里写图片描述
这里写图片描述
说明已经登陆成功,而且产生了本次访问的token!

将token记录下来,接着测试。 继续测试一个查询的功能: http://127.0.0.1:8102/xygerp/albc/swagger-ui.html

这里写图片描述

注意,这里用了Spring Security框架,因此的API请求头都必须携带token信息。不然请求会返回401。

若是测试OK,那说明基本上系统已经成功搭建好了。 下一步就是如何在测试环境或者正式环境部署它,以及如何一键构建项目的问题了。

简单来讲,系统的部署是用 docker工具 ,一键部署项目用的是 Jenkins工具。后面将会用专题来讲明这2个工具的使用。

3.6 该API微服务系统实现的功能难点

3.6.1 解决数据库Session的环境变量问题,特别是语言环境和用户环境。

关于这个问题,目前我用的办法可能不必定是最优的,若是有别的兄台有更好的解决办法,请留言给我,十分感谢!

问题来源:

熟悉EBS开发的兄台都应该知道,登陆ERP以后,咱们每次打开Form,系统就会申请一个新的数据库Session,这时候,EBS系统会 自动帮咱们初始化该Session的环境变量 :例如基本的语言环境,用户环境,业务实体等等。

这时候,咱们在包里面能够直接用FND_GLOBAL.USER_ID之类的函数就能够很是方便获取环境变量的信息。

可是,在Java Web开发里面就不同了!

在Java访问数据库的理念中,Session的申请是一个极耗资源的动做!因此,大部分链接数据库的Java软件都提出了一个 数据库链接池 的概念(例如DRUID数据库链接池)。简单来讲就是session共用!

Session公用就会带来一个并发问题:A用户使用系统,并初始化了该Session的环境变量为A用户;当A用户不用系统的时候,Session会闲置并放回链接池里面等待别的用户使用。

这时候若是B的用户极可能会使用该Session,若是不从新初始化环境变量的话,那B用户使用系统的Session的环境变量仍是A用户,就会致使数据的bug! 如何处理该问题是开发该系统碰到的一个难题。

问题解决:

我目前的处理办法是:在Service层,用AOP统一自动监控Service层的这个参数AuthUser user

只要在Service层将参数AuthUser user放在最后,AOP会自动初始化Session的环境变量。(须要注意的是,我这个系统的数据库Transaction在Service层启用!)

另外,语言环境变量,登陆ID环境变量等,会一并自动初始化。由于AuthUser会携带该定义!

核心处理代码以下:

private static final String SQL_GLOBAL_INIT
	    = " DECLARE "
		+ " L_session_id NUMBER;L_user_id NUMBER;L_login_id NUMBER;L_LANG VARCHAR2(10); "
		+ " BEGIN "
		+ " L_user_id:=:P_USER_ID; L_login_id:=:P_LOGIN_ID; L_LANG:=:P_LANG;"
		+ " APPS.fnd_global.INITIALIZE("
		+ " session_id=>L_session_id, user_id =>L_user_id, resp_id =>NULL, "
		+ " resp_appl_id=>NULL, security_group_id=>NULL, site_id=>NULL, login_id =>L_login_id, "
		+ " conc_login_id=>NULL, prog_appl_id=>NULL, conc_program_id=>NULL, conc_request_id=>NULL, "
		+ " conc_priority_request=>NULL"
		+ " ); "
		+ " IF NVL(L_LANG,'US') <> USERENV('LANG') THEN "
		+ " IF L_LANG='ZHS' THEN "
		+ " APPS.fnd_global.set_nls_context(p_nls_language => 'SIMPLIFIED CHINESE'); "
		+ " ELSE "
		+ " APPS.fnd_global.set_nls_context(p_nls_language => 'AMERICAN'); "
		+ " END IF;"
		+ " END IF;"
		+ " END; ";
	
    /*** 
     * service层调用以前先自动初始化环境变量
     * 须要注意的是,用户变量必须的参数放在最后!
     * 只要在Service层将参数AuthUser user放在最后,AOP会自动初始化Session的环境变量。
     * @throws Exception 
     */  
	@SuppressWarnings("static-access")
	@Before("execution(* com.jebms.*.service..*.*(..)) && args(..,user)")  
    public void oracleDBInit(JoinPoint joinPoint,AuthUser user) throws Exception{
		Long dbLoginId=devDao.getJdbcTemplate().queryForObject("SELECT FND_GLOBAL.LOGIN_ID FROM DUAL", Long.class);
if(user.getLoginId()!=null&&user.getLoginId()>0&&!user.getLoginId().equals(dbLoginId)){
			Map<String,Object> inParamMap=new HashMap<String,Object>();
	    	inParamMap.put("P_USER_ID", user.getUserId());
	    	inParamMap.put("P_LOGIN_ID", user.getLoginId());
	    	inParamMap.put("P_LANG", user.getLanguage());
			devDao.getDevJdbcTemplate().execute(this.SQL_GLOBAL_INIT, inParamMap);
        }
    }

复制代码

源代码在:com.jebms.comm.utils. AopUtil

3.6.2 解决EBS的用户的登陆问题:统一用EBS系统的账号密码登陆API系统。

问题描述:

因为我这个是第三方的API系统,因此,用户名和密码信息实际上并非该API系统须要管理的事情。

至关于说,API系统没法按照正常的流程来验证用户名和密码:输入用户名和密码,系统验证后台数据库的用户名和密码,再返回验证结果。

而是:输入用户名和密码,系统 调用ERP的用户名密码验证包 进行验证,再返回结果。 简单来讲:须要添加自定义验证的逻辑。

还好Spring Security框架支持灵活的验证逻辑。

添加步骤:

首先,写一个自定义验证的类:MyAuthenticationProvider

接着,在Spring Security框架的定义中,添加这个自定义的验证。

AbstractWebSecurityConfig

private MyAuthenticationProvider provider;//自定义验证 auth.authenticationProvider(provider);

便可以完美实现这个效果

核心代码:

/**
     * 自定义验证方式
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();
        AuthUser user = (AuthUser) userService.loadUserByUsername(username);
        System.out.println("username:"+username+",password:"+password);
        if(user == null){
            throw new BadCredentialsException("Username not found.");
        }

        //加密过程在这里体现
        if (!sysService.xygErpValidateLogin(username, password)) {
            throw new BadCredentialsException("Wrong password.");
        }
        
        user.setPassword(passwordEncoder.encode(password));

        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
        return new UsernamePasswordAuthenticationToken(user, password, authorities);
    }

复制代码

3.6.3 统一的开发风格。

1.Entity基类封装。

封装了5who栏位,以及相似Form的FND_SET_WHO的方法,能够很方便进行开发。

另外,为了防止丢失更新,这边每次更新前实际上会先检测数据的一致性,对应的动做也有作了封装。

2.查询逻辑的封装。

查询功能相对来讲仍是会不少,对于复杂的查询条件如何传值是一个难题。

这里封装了一个SearchInfo积累,能够统一将全部的查询条件都放在这个类,而后在java的Controller层定义好查询条件对应匹配栏位,系统就能够自动产生对应的and条件。

例如:

@GetMapping(value = "/getPageLocator")
    @ApiOperation(value = "货位分页列表接口")
    public ResultEntity<PageInfo<EslipLocatorRE>> getPageLocator(
    		@ApiParam(value = "库存组织ID",required = true) @RequestParam(required = true) int organizationId,
    		@ApiParam(value = "库别代码",required = true) @RequestParam(required = true) String subinventoryCode,
    		@ApiParam(value = "货位代码",required = false) @RequestParam(required = false) String locatorCode,
    		SearchInfo searchInfo) throws Exception {
    	searchInfo.getConditionMap().put("organizationId", organizationId);
    	searchInfo.getConditionMap().put("subinventoryCode", subinventoryCode);
    	searchInfo.getConditionMap().put("locatorCode", locatorCode);
    	searchInfo.setAuthUser(this.authUser);
    	searchInfo.initSqlCondition();
    	searchInfo.andSqlCondition("MIL.ORGANIZATION_ID","organizationId");
    	searchInfo.andSqlCondition("MIL.SUBINVENTORY_CODE","subinventoryCode");
    	searchInfo.andSqlCondition("MIL.SEGMENT1","locatorCode");
        return eslipService.selectForPageLocator(searchInfo);
    }

复制代码

3.统一的处理结果的封装。

基本上任何一个处理,要不成功,要不失败(警告其实也算失败)。

这里封装了一个返回结果的基类ResultEntity<T>,能够进行有效的应用端或者java端的交互。

这里写图片描述

@ApiModelProperty(value = "状态码,0表示成功 其余表示失败", example = "0",position = 1)
private String code;
复制代码

特别须要指出的是,前端获取或者处理数据,也是统一要用这个处理结果基类的返回。

简单来讲,就是数据处理成功/失败,会有一个统一的返回结果标识。注意,这个标识和请求的响应结果标识(200)是有所不一样的!

请求响应标识只是说明web服务器的响应是正常,但,具体的处理结果多是处理失败。

这里写图片描述

下面是一个具体的例子(到时候实际开发处理的接口处理结果也是这样子):

{
	"code": "0",
	"message": "",
	"description": "",
	"obj": [{
		"createdBy": -1,
		"creationDate": "2017-10-10 09:37:03",
		"lastUpdatedBy": 10,
		"lastUpdateDate": "2017-11-16 14:47:48",
		"lastUpdateLogin": 96,
		"valueUUID": null,
		"id": 2,
		"applId": 1,
		"respCode": "BASIC_SET",
		"menuId": 2,
		"startDate": "2017-10-10 09:37:03",
		"endDate": null,
		"respName": "系统设置职责",
		"description": "系统设置职责",
		"menuCode": "SYSTEM_SET",
		"menuName": "系统设置菜单",
		"enabled": true
	}],
	"param1": null,
	"param2": null,
	"param3": null,
	"param4": null,
	"param5": null,
	"ok": true
}

复制代码

文档参考连接: https://juejin.im/entry/5a7812906fb9a0635014f19a http://blog.51cto.com/ityouknow/1974080

相关文章
相关标签/搜索