SSM项目——开放平台管理平台(开放源码)
l
文章目录
- 一、 引言
- 1.1 开放平台介绍
- 1.2 开放平台的使用场景
- 二 、开放平台之管理平台
- 2.1 管理平台介绍
- 2.2 客户管理
- 2.2.1 介绍
- 2.2.2 功能展示
- 2.2.2 数据库结构
- 2.3 应用管理
- 2.3.1 介绍
- 2.3.2 功能展示
- 2.3.3 数据库结构
- 2.4 路由管理
- 2.4.1 介绍
- 2.4.2 功能展示
- 2.4.3 数据库结构
- 2.5 系统参数管理
- 2.5.1 介绍
- 2.5.2 功能展示
- 2.5.3 数据库结构
- 2.6 Token 管理
- 2.6.1 介绍
- 2.6.2 功能展示
- 2.6.3 数据库结构
- 2.7 充值管理
- 2.7.1 介绍
- 2.7.2 功能展示
- 2.7.3 数据库结构
- 三 、技术架构
- 3.1 架构技术点
- 3.2 所需工具
- 四 、编码规范
- 五、 编码顺序
- 六、 功能实现
- 6.1 客户管理
- 6.1.1 环境搭建,创建Maven项目(打包方式为war)及导入依赖
- 6.1.2 数据库配置文件
- 6.1.3 spring和mybatis相关配置文件
- 6.1.4 springMVC的配置文件
- 6.1.5 web.xml的配置
- 6.1.6 客户表的创建及pojo的创建
- 6.1.7 客户管理的Mapper
- 6.1.8 客户管理的service
- 6.1.9 创建CustomerController并测试Controller添加客户信息
- 6.1.10 index首页展示
- 6.1.11 编写customer.html页面
- 6.1.12 Customer的添加
- 6.1.13 删除客户信息
- 6.1.14 按条件查询
- 6.2 应用管理
- 6.2.1 创建数据库表及生体实体类
- 6.2.2 应用管理的Mapper
- 6.2.3 应用管理的service
- 6.2.4 应用管理的controller
- 6.2.5 appinfo.html页面列表展示
- 6.2.6 编写获取客户列表的Controller方法
- 6.2.7 添加应用
- 6.2.8 更新应用
- 6.2.9 按条件查询可参考客户管理的搜索
- 6.3 登录功能
- 6.3.1 创建login.html页面,并实现登录请求的js代码
- 6.3.2 创建数据库表及AdminUser实体类
- 6.3.3 编写AdminUserController
- 6.3.3 AdminUserService的编写
- 6.3.4 AdminUserMapper编写
- 6.4 实现不同用户登录看到不同菜单 RBAC 基于角色的权限访问控制
- 6.4.1 index.html页面的改造,展示菜单区域变成动态填充
- 6.4.2 通过请求填充左侧菜单栏
- 6.4.3 创建数据库表及Menu实体类
- 6.4.4 MenuController的编写
- 6.4.5 MenuService 的编写
- 6.4.6 MenuMapper 的编写
- 6.4.7 makeMenuTree方法编写
- 6.4.8 编写相应的常量
一、 引言
1.1 开放平台介绍
开放平台(Open Platform) 在软件行业和网络中,开放平台是指软件系统通过公开其应用程序编程接口(API)或函数(function)来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源,而不需要更改该软件系统的源代码。在互联网时代,把网站的服务封装成一系列计算机易识别的数据接口开放出去,供第三方开发者使用,这种行为就叫做Open API,提供开放API的平台本身就被称为开放平台。
1.2 开放平台的使用场景
企业要调用别人的长板,通过API技术,互相调用、与行业形成链接。在借助他人长板的同时,也把自己的长板贡献给他人,就是互相赋能。
开放平台的作用简单地说就是通过第三方的力量来扩展自己的生态和能力,因为光凭自己做的软件并不能覆盖所有的场景,例如阿里、京东可以提供标准化的应用软件,可能满足于一些小的卖家使用,但是数百万形形色色的卖家对于个性化要求的软件,并不是一个公司的力量可以满足的,所以就把这些需求开放给众多的第三方开发者。
开放平台使用广泛、几乎所有的互联网公司都有自己的开放平台,知名的如京东的宙斯(JD Open Platform), 淘宝开放平台(Taobao Open Platform),百度的数据开放平台(https://open.baidu.com),大公司的开放平台都是一个完整的生态链,有很多第三方开发者(ISV),专门根据大的平台开放的接口,来开发出一些通用的软件,比如“E店宝”,依赖于淘宝、天猫、京东、拼多多等大型电商开放的接口,开发出的电商ERP的管理软件,通过这个 ERP 可以直接执行淘宝,京东等电商对外提供的功能,如查看订单,退货,上架产品等等
开放平台项目 |
---|
二 、开放平台之管理平台
2.1 管理平台介绍
管理平台主要是对开放平台中的一些数据进行综合性管理,如客户管理,应用管理,充值管理,api 路由管理,网关参数管理,用户 Token 管理,日志搜索,权限管理,实现对服务的限流,熔断等动态配置,通过管理平台可以查看生成的数据,也可以通过管理平台将修改的数据同步到开放平台的网关系统中来实现实时更新功能
管理平台部分功能展示 |
---|
2.2 客户管理
2.2.1 介绍
客户指的是注册了开放平台并通过平台来获取相应数据的人,如我们的淘宝账号可以通过淘宝的开放平台提供的 API 来实现对淘宝的一些功能的调用,如订单管理,商品管理等
客户主要包含的主要信息包括 用户名,密码,公司名称,账户余额,公司地址,账户状态等
客户管理主要是针对在开放平台上注册的用户进行管理, 可以对用户的账号密码,企业名称,账户余额等内容进行管理,并且可以代用户进行注册,编辑删除账户等操作
2.2.2 功能展示
客户管理功能展示 |
---|
2.2.2 数据库结构
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
username | String | 用户名 |
password | String | 密码 |
nickname | String | 公司名称 |
address | String | 地址 |
money | int | 余额(毫) |
state | int | 状态 1 正常,0 停用 |
2.3 应用管理
2.3.1 介绍
应用指的是客户在我们的平台创建的应用,一个客户可以创建多个应用,比如 抖音,今日头条,火山视频都是字节跳动的产品,它们都使用了微信分享和登陆这些开放功能,那么在微信的开放平台中,字节跳动就是一个客户,而抖音,今日头条都是字节跳动下面不同的应用,他们需要分别在微信开放平台创建出来才可以使用微信开放的功能
应用主要包含的主要信息为所属客户,应用名称,应用的 key,应用的秘钥(签名用),应用接收信息的回调 URL,应用对开放平台中接口的免费调用次数,应用描述等,关联功能客户管理
应用管理中主要包含创建应用,展示应用的相关信息,编辑修改应用,以及批量删除等操作,让管理人员可以随时通过对应用的信息修改来实现动态实时的限制
2.3.2 功能展示
应用管理功能展示 |
---|
2.3.3 数据库结构
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
corpName | String | 关联企业名称,冗余减少查询 |
appName | String | 应用名称 |
appKey | String | 应用唯一标示 KEY |
AppSecret | String | 应用签名秘钥 |
redirectUrl | String | 应用回调用 URL |
linit | int | 免费接口日调用限制次数 |
description | String | 应用介绍 |
cusId | int | 关联客户 id |
state | int | 状态 |
2.4 路由管理
2.4.1 介绍
在开放平台中,因为开放的服务的数量不确定,有的服务可能今年开放的,有的服务可能是明年新开发后开放的,有的服务可能过来一段时间后下线了,这一切都可能是随时变化的,因为如果每个服务都单独开发一套接口来让客户调用的话就变得非常繁琐,无法实现动态的调整,就像一个公司会有很多部门,每个部门都会招聘人,如果每个部门的招聘信息上面都写对应部门的人的话,就会变得很麻烦,我们需要在公司前台那里给每个部分留一个面试官,会浪费人员,最合适的办法是我们只要都留公司前台地址就行,我们只需要告诉前台每个部门的对接人信息就行,来面试的人员只要说明自己来面试哪个部门即可,前台会根据部门来找到对接人然后通知对接人即可,那么个前台就是统一的入口,她记录的对接人的信息就属于路由信息,我们只需要和前台沟通随时变更对接人信息即可,以后多了新部门只要和前台说新部门的信息即可
路由主要包含的主要信息为 路由的标识,对应的真正服务 id,对应服务的地址,描述信息,服务状态,幂等性,是否收费等
路由管理主要是对路由信息的添加,修改,启用,停用,幂等性状态修改, 是否收费等进行相关管理
2.4.2 功能展示
路由管理功能展示 |
---|
2.4.3 数据库结构
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
gatewayApiName | String | 路由名称标识 |
insideApiUrl | String | 服务接口地址 |
serviceId | String | 服务名称 |
description | String | 介绍信息 |
state | int | 状态 1 有效,0 无效 |
idempotents | int | 幂等性 1 幂等 0 非幂等 |
needfee | int | 是否收费 1 收费 0 免费 |
2.5 系统参数管理
2.5.1 介绍
我们的所有的服务在请求之前会要求我们必须传递某些名字的参数,就像我们去一家公司面试的时候不管面试的是什么部门都要带简历一样,这些参数我们成为系统参数
系统参数包含的主要信息是 参数名称,参数描述,参数状态
系统参数管理主要是针对我们网关中请求时候需要的系统参数进行管理,可以动态添加或者修改删除参数,修改后同步到网关中,网关即可实现动态参数校验的功能
2.5.2 功能展示
系统参数管理功能展示 |
---|
2.5.3 数据库结构
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
name | String | 参数名 |
description | String | 参数介绍 |
state | int | 状态 1 启用,0 禁用 |
2.6 Token 管理
2.6.1 介绍
我们在访问功能的时候需要用登陆,单体项目的时候我们可以使用 session 来记录数据,但是在分布式系统中,session 共享比较复杂,所以我们会使用其他方式来记录这些状态,我们会在用户首次登陆的时候给他生成一个 token,下次用户带着 token 来我们进行校验即可
令牌在数据库中主要的信息为客户 id,token 内容,开始时间,过期时间等信息,关联客户信息
Token 管理主要是管理用户登录后生成的 token数据,修改有效期,删除等
2.6.2 功能展示
Token 管理功能展示 |
---|
2.6.3 数据库结构
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
userId | int | 客户 id |
access_token | String | token 内容 |
startTime | DateTime | 开始时间 |
expireTime | DateTime | 结束时间 |
2.7 充值管理
2.7.1 介绍
开放平台中部分接口的访问是需要收费的,因为用户需要先充值才可以使用
充值的数据信息主要是客户id,订单号,充值金额,日期,付费方式,状态等信息
充值管理主要是查看用户的充值记录,并且可以在自动充值出现问题的时候手动为用户充值
2.7.2 功能展示
充值管理功能展示 |
---|
2.7.3 数据库结构
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
cusId | int | 客户 id |
createtime | DateTime | 创建订单时间 |
updateTime | DateTime | 更新时间 |
state | int | 状态,0未支付,1 已支付,2 已取消 |
paymenttype | int | 支付类型 0 银联,1 微信,2支付宝 |
三 、技术架构
我们的项目是一个管理平台,大部分的管理平台都是对内提供功能或者给用户提供部分可选功能,所以相对起来比较简单,大部分使用的是SSM单体架构,我们当前的项目也是采取的SSM架构
3.1 架构技术点
技术名称 | 针对的功能 | 介绍 | 版本 |
---|---|---|---|
SpringMVC | 控制层 | 主要用作于接收用户请求,封装参数,返回数据 | 5.1.x |
Spring | 对象管理 | 主要对我们项目需要的对象进行生命周期管理 | 5.1.x |
Mybatis | 持久层 | 主要是用于我们和数据库进行交互 | 3.5.x |
Quartz | 定时任务 | 比如定时备份数据 | 1.5.x |
LayUI | 前端展示 | 用于显示页面数据,传递数据到控制层 | 2.5.x |
3.2 所需工具
工具名称 | 功能 | 介绍 |
---|---|---|
Intellij Idea | 代码开发 | 开发集成编辑器 |
Maven | 项目管理 | 项目构建管理工具 |
Maven Helper | 快速运行maven操作 | 一款IDEA插件,可以自定义执行maven指令 |
MySQL | 持久化数据 | 免费开源的数据库 |
Tomcat | 运行容器 | 基于Java Servlet规范的容器 |
VS Code | 文本编辑 | 免费开源的文本编辑器 |
四 、编码规范
本规范主要是针对开发中我们的一些基本内容进行规范约束定义,包含项目的包名,对应的文件位置等
名称 | 规范 |
---|---|
包名 | com.qianfeng.openapi.web.master |
控制层包名 | controller |
服务层包名 | servcie/impl |
数据层包名 | mapper |
工具类包名 | utils |
数据库对象包名 | pojo |
view对象包名 | bean |
mapper xml | resouces目录下与接口包名对应的目录 |
spring配置文件 | resouces下spring目录 |
mybatis配置文件 | resouces下mybatis目录 |
其他配置文件 | resouces下conf目录 |
变量名 | 驼峰命名 |
状态码 | 接口中定义常量 |
其他规范 | 具体情况具体定义 |
五、 编码顺序
在我们的实际开发中,我们会遇到选择的问题,就是到底是先写controller还是service还是dao,其实先写谁都可以,这个取决于我们自己的角度,如果你先想我们的项目有什么业务,那么我们一般会先写service,另外一个方面,我们分析出数据库的表结构后,可以先写数据库相关的操作,也就是我们的dao,也可以先想一下我们会和前端做什么交互,先写controller,这个完全取决于我们的角度,当然如果不是前后端分离的项目,页面是我们写的,我们也可以按照需求先把页面写出来
六、 功能实现
6.1 客户管理
6.1.1 环境搭建,创建Maven项目(打包方式为war)及导入依赖
项目相关依赖
<dependencies><!--webmvc--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.6.RELEASE</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version></dependency><!--mybatis整合spring--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.4</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version><scope>runtime</scope></dependency><!--连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency><!--jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.6.RELEASE</version></dependency><!--pagehelper--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version></dependency><!--jackson--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.10.2</version></dependency><!--aspectj--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><!--servlet-api--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency></dependencies>
6.1.2 数据库配置文件
在resources文件夹下创建一个conf文件夹,存放jdbc.properties文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///open_demo?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123
6.1.3 spring和mybatis相关配置文件
在resources文件夹下创建一个spring文件夹,存放spring相关文件,例如spring-context.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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--扫描servcie--><context:component-scan base-package="com.qianfeng.openapi.web.master.service"/></beans>
在resources文件夹下创建一个mybatis文件夹,存放mybatis主配置文件,例如mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!--MyBatis配置-->
<configuration><settings><!--打印查询SQL语句--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><!--pagehelper插件--><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><!--配置数据库方言--><property name="helperDialect" value="mysql"/></plugin></plugins>
</configuration>
创建spring和mybatis整合的配置文件,spring-mybatis.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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--配置文件参数化(参数占位符)--><context:property-placeholder location="classpath:conf/jdbc.properties" /><!--与DruidDataSource集成(二选一)--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><!--基本配置--><property name="driverClassName" value="${jdbc.driverClass}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!-- 工厂bean:生成SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入连接池 --><property name="dataSource" ref="dataSource"></property><!-- 注入dao-mapper文件信息 ,如果映射文件和dao接口 同包且同名,则此配置可省略--><property name="mapperLocations" value="classpath:com/qianfeng/openapi/web/master/mapper/*.xml"/><!--加载mybatis主配置文件--><property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/><!--别名--><property name="typeAliasesPackage" value="com.qianfeng.openapi.web.master.pojo"/></bean><!-- mapperScannerConfigurer --><bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.qianfeng.openapi.web.master.mapper"/><!-- 如果工厂中只有一个SqlSessionFactory的bean,此配置可省略 --><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean></beans>
创建spring和事务整合的配置文件,spring-transaction.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:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 1. 引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑 --><bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><tx:advice id="txManager" transaction-manager="tx"><tx:attributes><tx:method name="get*" read-only="true"/><tx:method name="query*" read-only="true"/><tx:method name="select*" read-only="true"/><tx:method name="find*" read-only="true"/><!-- 剩余所有方法 --><tx:method name="*"/></tx:attributes></tx:advice><aop:config><aop:pointcut expression="execution(* com.qianfeng.openapi.web.master.service..*.*(..))" id="pc"/><!-- 组织切面 --><aop:advisor advice-ref="txManager" pointcut-ref="pc"/></aop:config>
</beans>
6.1.4 springMVC的配置文件
在spring文件夹下创建springmvc的主配置文件,springmvc.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:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--扫描controller--><context:component-scan base-package="com.qianfeng.openapi.web.master.controller"/><!--配置各种适配器--><mvc:annotation-driven/><!--放行静态资源 --><mvc:default-servlet-handler/>
</beans>
6.1.5 web.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/spring-*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--放行html文件--><servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.html</url-pattern></servlet-mapping><servlet><servlet-name>mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 局部参数:声明配置文件位置 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/springmvc.xml</param-value></init-param><!-- Servlet启动时刻:可选 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>mvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- 此过滤器会进行:request.setCharactorEncoding("utf-8"); --><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>
6.1.6 客户表的创建及pojo的创建
Customer类
public class Customer{private Long id;private String username;private String password;private String nickname;private Integer money;private String address;private Integer state;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public Integer getMoney() {return money;}public void setMoney(Integer money) {this.money = money;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Integer getState() {return state;}public void setState(Integer state) {this.state = state;}
6.1.7 客户管理的Mapper
CustomerMapper接口中定义CRUD方法
int insertCustomer(Customer customer);int updateCustomer(Customer customer);int deleteCustomer(Long id);Customer getCustomerById(Long id);List<Customer> getAllCustomers();
在resources文件夹下创建和src中mapper路径一样的包,并放置CustomerMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qianfeng.openapi.web.master.mapper.CustomerMapper"><insert id="insertCustomer" parameterType="customer" useGeneratedKeys="true" keyProperty="id">insert into customer values(null,#{username},#{password},#{nickname},#{money},#{address},#{state})</insert><update id="updateCustomer">update customer set<trim suffixOverrides=","><if test="username!=null and username!=''">username=#{username},</if><if test="password!=null and password!=''">password=#{password},</if><if test="nickname!=null and nickname!=''">nickname=#{nickname},</if><if test="money!=null and money!=''">money=#{money},</if><if test="address!=null and address!=''">address=#{address},</if><if test="state!=null">state=#{state},</if></trim>where id=#{id}</update><delete id="deleteCustomer">DELETE from customer where id =#{id}</delete><select id="getCustomerById" resultType="com.qianfeng.openapi.web.master.pojo.Customer">SELECT * from customer where id =#{id}</select><select id="getAllCustomers" resultType="com.qianfeng.openapi.web.master.pojo.Customer">SELECT * from customer</select></mapper>
6.1.8 客户管理的service
创建ICustomerService接口,放置和Mapper接口中一样的方法
int insertCustomer(Customer customer);int updateCustomer(Customer customer);int deleteCustomer(Long id);Customer getCustomerById(Long id);List<Customer> getAllCustomers();
创建ICustomerService接口实现类CustomerServiceImpl,并实现每个方法
@Service
public class CustomerServiceImpl implements ICustomerService {@Autowiredprivate CustomerMapper customerMapper;@Overridepublic int insertCustomer(Customer customer) {return customerMapper.insertCustomer(customer);}@Overridepublic int updateCustomer(Customer customer) {//判断ID是否为空if (customer.getId() != null) {return customerMapper.updateCustomer(customer);}else{//给予提示//TODO}return 0;}@Overridepublic int deleteCustomer(Long id) {if (id != null) {return customerMapper.deleteCustomer(id);}else{//给予提示//TODO}return 0;}@Overridepublic Customer getCustomerById(Long id) {if (id != null) {return customerMapper.getCustomerById(id);}else{//给予提示//TODO}return null;}@Overridepublic List<Customer> getAllCustomers() {return customerMapper.getAllCustomers();}
}
6.1.9 创建CustomerController并测试Controller添加客户信息
可以通过postman访问添加客户接口,并传递参数值
@RestController
@RequestMapping("/sys/customer")
public class CustomerController {@Autowiredprivate ICustomerService customerService;@PostMapping("/add")public String add(Customer customer) {customerService.insertCustomer(customer);return "SUCCESS";}}
6.1.10 index首页展示
创建webapp文件夹,创建index.html页面,页面代码是从layui中获取后端模版首页的界面代码,并引入css,js文件。后端模板界面网址:https://www.layui.com/doc/element/layout.html#admin
项目中还需要导入layui文件夹
在webapp下创建一个sys文件夹,放入customer.html文件。先测试能跳转到customer.html,再修改跳转到客户管理的页面地址,如下:
<li class="layui-nav-item"><a href="javascript:" onclick="openRight('/sys/customer.html')">客户管理</a>
</li><div class="layui-body" id="main"></div><script src="layui/layui.js"></script>
<script src="layui/jquery-1.10.2.min.js"></script>
<script> function openRight(url) {$(function(){$("#main").load(url);})}
</script>
6.1.11 编写customer.html页面
导入已经画好的customer.html页面,然后写相应的js代码
编写展示列表信息的代码,需要创建一个TableData来接收查询到的数据,并返回给页面的table的cols属性使用
public class TableData<T> {private int code = 0;private String msg;private Long count; //总条数private List<T> data;//集合数据public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Long getCount() {return count;}public void setCount(Long count) {this.count = count;}public List<T> getData() {return data;}public void setData(List<T> data) {this.data = data;}
}
页面展示列表信息js代码
/*手动进行渲染*/layui.use(['table','layer','form'],function () {/*实例化*/var table = layui.table;var layer = layui.layer;var form = layui.form;form.render();//进行渲染table.render({id:"customer-table",/*指定原始 table 容器的选择器*/elem:"#customer-table",/*toolbar: true //仅开启工具栏*/toolbar:"#customer-head-bar",/*开启分页*/page : true,/*数据格式解析的回调函数,用于将返回的任意数据格式解析成 table 组件规定的数据格式。*/url:"/sys/customer/table",/*设置表头。值是一个二维数组。方法渲染方式必填*/cols:[[{checkbox:true},{field: 'id', title: '编号', sort: true},{field: 'username', title: '用户名'},{field: 'nickname', title: '昵称'},{field: 'address', title: '地址'},{field: 'money', title: '余额'},{field: 'state', title: '状态',templet:function (data) { /*templet自定义列模板*/return (data.state==1)?'<span class="layui-badge layui-bg-green">有效</span>':'<span class="layui-badge layui-bg-red">无效</span>'}},{field:'right',title:'操作',toolbar:'#customer-customer-bar',width:150}]]})});
CustomerController中的编码
/*** 渲染customer页面表格数据* @param page* @param limit* @return*/@GetMapping("table")public TableData<Customer> table(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "5") Integer limit) {TableData<Customer> tableData = new TableData<>();//page,limit,为分页的当前页和每面显示条数PageInfo<Customer> pageInfo = customerService.getCustomerByPage(page, limit);// 设置tableData.setCount(pageInfo.getTotal());tableData.setData(pageInfo.getList());return tableData;}
CustomerServiceImpl类中的编码
@Overridepublic PageInfo<Customer> getCustomerByPage(Integer page, Integer limit) {PageHelper.startPage(page,limit);List<Customer> customerList = customerMapper.getAllCustomers();return new PageInfo<>(customerList);}
CustomerMapper.xml文件的编码
<select id="getAllCustomers" resultType="com.qianfeng.openapi.web.master.pojo.Customer">SELECT * from customer</select>
6.1.12 Customer的添加
customer页面js的编写,注意,此监听事件依然放在 layui.use()中
/*监听事件*//*语法:table.on('event(filter)', callback); 注:event为内置事件名,filter为容器lay-filter设定的值*/table.on('toolbar(customer-table)', function(obj){switch (obj.event){//判断事件类别case 'goEdit':openEditWindow(null);break;case 'delete':/*获取选中行的数据*/var data = table.checkStatus("customer-table").data;if(data.length>0){layer.confirm("确定要删除吗?",function (index) {var params = "";$.each(data,function (i, obj) {params+="&ids="+obj.id;})$.ajax({url:"/sys/customer/delete",data:params,method:"post",success:function (result) {if(result.state){table.reload("customer-table",{})}else{alert(result.message);/*提示信息*/}layer.close(index);/*关闭窗口*/}})})}break;}});
openEditWindow(data)方法的编写,此方法可做修改和新增客户的操作
/*编辑和添加的方法*/function openEditWindow(data) {/*弹出框*/layer.open({type: 1,content: data==null ?$("#customer-add-layer").html():$("#customer-edit-layer").html(),title:'编辑',area:['500px','400px'],btn:['提交','取消'],yes:function (index, layero) {/*确定按钮回调方法*/layer.load();/*加载层*/$.ajax({url:"/sys/customer/"+(data==null?'add':'update'),data:data==null?$("#customer-add-form").serialize():$("#customer-edit-form").serialize(),method:"POST",success:function(result){if(result.state){ /*状态是true*/table.reload('customer-table',{});/*表格重载,第二个参数为可选项*/layer.close(index); //如果设定了yes回调,需进行手工关闭}else{alert(result.message);}layer.closeAll("loading");/*loading为css样式*/}})},success:function (index, layero) {/*层弹出后的成功回调方法*/form.render();if(data!=null){/*语法:form.val('filter', object);用于给指定表单集合的元素赋值和取值。如果 object 参数存在,则为赋值;如果 object 参数不存在,则为取值。*/form.val("customer-edit-form",data);form.val("customer-edit-form",{"state":data.state+""});}}})}
定义返回结果类AjaxResponse
public class AjaxResponse {private boolean state;private String message;private Object result;public boolean isState() {return state;}public void setState(boolean state) {this.state = state;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public Object getResult() {return result;}public void setResult(Object result) {this.result = result;}public AjaxResponse() {}public AjaxResponse(boolean state, String message) {this.state = state;this.message = message;}public AjaxResponse(boolean state, String message, Object result) {this.state = state;this.message = message;this.result = result;}
}
CustomerController类中的添加客户方法
@RestController
@RequestMapping("/sys/customer")
public class CustomerController {@Autowiredprivate ICustomerService customerService;@PostMapping("/add")public AjaxResponse add(Customer customer) {try{customerService.insertCustomer(customer);return new AjaxResponse(true,"添加成功!");}catch (Exception e){return new AjaxResponse(false,"添加失败!");}}}
修改的js代码,注意,此监听事件依然放在 layui.use()中
/*监听工具条*/table.on('tool(customer-table)',function (obj) {var data = obj.data; /*用于编辑页面的数据回显,只要json中的属性名和name中的属性名称一样即可回显*/switch (obj.event){case 'edit-customer':openEditWindow(data);break;}})
CustomerController中的修改客户信息代码
/*修改客户信息*/@PostMapping("/update")public AjaxResponse update(Customer customer){try{customerService.updateCustomer(customer);return new AjaxResponse(true,"修改成功!");}catch (Exception e){return new AjaxResponse(false,"修改失败!");}}
6.1.13 删除客户信息
CustomerController中的代码
/*删除客户信息*/@PostMapping("/delete")public AjaxResponse delete(long[] ids){try{customerService.deleteCustomers(ids);return new AjaxResponse(true,"删除成功!");}catch (Exception e){return new AjaxResponse(false,"删除失败!");}}
CustomerServiceImpl中的代码
@Override
public int deleteCustomers(long[] ids) {return customerMapper.deleteCustomersByIds(ids);
}
CustomerMapper中的代码
<!--批量删除-->
<delete id="deleteCustomersByIds">delete from customer where id IN<foreach collection="array" open="(" close=")" item="id" separator=",">#{id}</foreach>
</delete>
6.1.14 按条件查询
form表单中的提交改为如下方式,绑定单击事件
<input type="button" class="layui-btn" id="search" value="搜索"/>
customer页面中条件查询的js代码
/*按条件查询*/function search() {$("#search").click(function(){//获取用户名和状态var username = $("#username").val();var state = $("#state").val();layui.use(['table','layer','form'],function (data) {/*实例化*/var table = layui.table;var layer = layui.layer;var form = layui.form;form.render();//进行渲染table.render({id:"customer-table",/*指定原始 table 容器的选择器*/elem:"#customer-table",/*toolbar: true //仅开启工具栏*/toolbar:"#customer-head-bar",/*开启分页*/page : {limits: [5, 10, 15, 20, 25]},/*数据格式解析的回调函数,用于将返回的任意数据格式解析成 table 组件规定的数据格式。*/url:"/sys/customer/search?username="+username+"&state="+state,/*设置表头。值是一个二维数组。方法渲染方式必填*/cols:[[{checkbox:true},{field: 'id', title: '编号', sort: true},{field: 'username', title: '用户名'},{field: 'nickname', title: '昵称'},{field: 'address', title: '地址'},{field: 'money', title: '余额'},{field: 'state', title: '状态',templet:function (data) { /*templet自定义列模板*/return (data.state==1)?'<span class="layui-badge layui-bg-green">有效</span>':'<span class="layui-badge layui-bg-red">无效</span>'}},{field:'right',title:'操作',toolbar:'#customer-customer-bar',width:150}]]})})})}
改成页面加载的方式
$(function(){/*渲染表格数据*/render();/*按条件查询*/search();})
CustomerController中按条件查询的代码
@GetMapping("/search")public TableData<Customer> search(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "5") Integer limit,String username,Integer state) {TableData<Customer> tableData = new TableData<>();//page,limit,为分页的当前页和每面显示条数PageInfo<Customer> pageInfo = customerService.getCustomersByCondition(page,limit,username,state);// 设置tableData.setCount(pageInfo.getTotal());tableData.setData(pageInfo.getList());return tableData;}
CustomerServiceImpl中的代码
@Overridepublic PageInfo<Customer> getCustomersByCondition(Integer page, Integer limit, String username, Integer state) {PageHelper.startPage(page,limit);List<Customer> customerList = customerMapper.getCustomersByCondition(username,state);return new PageInfo<>(customerList);}
CustomerMapper接口
List<Customer> getCustomersByCondition(@Param("username") String username,@Param("state") Integer state);
CustomerMapper.xml文件
<select id="getCustomersByCondition" resultType="com.qianfeng.openapi.web.master.pojo.Customer">SELECT * from customer<where><if test="username!=null and username!=''">and username=#{username}</if><if test="state!=null">and state=#{state}</if></where></select>
6.2 应用管理
6.2.1 创建数据库表及生体实体类
AppInfo实体类
public class AppInfo{private Long id;private String corpName;private String appName;private String appKey;private String appSecret;private String redirectUrl;private Integer linit;private String description;private Long cusId;private Integer state;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getCorpName() {return corpName;}public void setCorpName(String corpName) {this.corpName = corpName;}public String getAppName() {return appName;}public void setAppName(String appName) {this.appName = appName;}public String getAppKey() {return appKey;}public void setAppKey(String appKey) {this.appKey = appKey;}public String getAppSecret() {return appSecret;}public void setAppSecret(String appSecret) {this.appSecret = appSecret;}public String getRedirectUrl() {return redirectUrl;}public void setRedirectUrl(String redirectUrl) {this.redirectUrl = redirectUrl;}public Integer getLinit() {return linit;}public void setLinit(Integer linit) {this.linit = linit;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public Long getCusId() {return cusId;}public void setCusId(Long cusId) {this.cusId = cusId;}public Integer getState() {return state;}public void setState(Integer state) {this.state = state;}
}
6.2.2 应用管理的Mapper
AppInfoMapper接口
public interface AppInfoMapper {int insertAppInfo(AppInfo appInfo);int updateAppInfo(AppInfo appInfo);int deleteAppInfoById(long id);int deleteAppInfoByIds(long[] ids);AppInfo getAppInfoById(long id);List<AppInfo> getAppInfos();
}
AppInfoMapper.xml文件编写
<insert id="insertAppInfo" parameterType="appInfo" useGeneratedKeys="true" keyProperty="id">insert into app_info values(null,#{corpName},#{appName},#{appKey},#{appSecret},#{redirectUrl},#{limit},#{description},#{cusId},#{state})</insert><update id="updateAppInfo">update app_info set<trim suffixOverrides=","><if test="corpName!=null and corpName!=''">corpName=#{corpName},</if><if test="appName!=null and appName!=''">appName=#{appName},</if><if test="appKey!=null and appKey!=''">appKey=#{appKey},</if><if test="appSecret!=null and appSecret!=''">appSecret=#{appSecret},</if><if test="redirectUrl!=null and redirectUrl!=''">redirectUrl=#{redirectUrl},</if><if test="limit!=null and limit!=''">linit=#{linit},</if><if test="description!=null and description!=''">description=#{description},</if><if test="cusId!=null and cusId!=''">cusId=#{cusId},</if><if test="state!=null">state=#{state},</if></trim>where id=#{id}</update><delete id="deleteAppInfoById">DELETE from app_info where id =#{id}</delete><!--批量删除--><delete id="deleteAppInfoByIds">delete from app_info where id IN<foreach collection="array" open="(" close=")" item="id" separator=",">#{id}</foreach></delete><select id="getAppInfoById" resultType="com.qianfeng.openapi.web.master.pojo.AppInfo">SELECT * from app_info where id =#{id}</select><select id="getAppInfos" resultType="com.qianfeng.openapi.web.master.pojo.AppInfo">SELECT * from app_info</select>
6.2.3 应用管理的service
IAppInfoSerivce的接口定义方法
int insertAppInfo(AppInfo appInfo);
int updateAppInfo(AppInfo appInfo);
int deleteAppInfoById(Long id);
int deleteAppInfoByIds(Long[] ids);
AppInfo getAppInfoById(Long id);
List<AppInfo> getAppInfos();
//查询分页
PageInfo<AppInfo> getAppInfoByPage(Integer page,Integer limit);
AppInfoSerivce的接口的实现类AppInfoServiceImpl
@Service
public class AppInfoServiceImpl implements IAppInfoService {@Autowiredprivate AppInfoMapper appInfoMapper;@Overridepublic int insertAppInfo(AppInfo appInfo) {return appInfoMapper.insertAppInfo(appInfo);}@Overridepublic int updateAppInfo(AppInfo appInfo) {return appInfoMapper.updateAppInfo(appInfo);}@Overridepublic int deleteAppInfoById(Long id) {return appInfoMapper.deleteAppInfoById(id);}@Overridepublic int deleteAppInfoByIds(Long[] ids) {return appInfoMapper.deleteAppInfoByIds(ids);}@Overridepublic AppInfo getAppInfoById(Long id) {return appInfoMapper.getAppInfoById(id);}@Overridepublic List<AppInfo> getAppInfos() {return appInfoMapper.getAppInfos();}@Overridepublic PageInfo<AppInfo> getAppInfoByPage(Integer page, Integer limit) {PageHelper.startPage(page,limit);List<AppInfo> appInfoList = appInfoMapper.getAppInfos();return new PageInfo<>(appInfoList);}
}
6.2.4 应用管理的controller
AppInfoController的编写
@RestController
@RequestMapping("/sys/appinfo")
public class AppInfoController {@Autowiredprivate IAppInfoService appInfoService;@PostMapping("/add")public AjaxResponse insertAppInfo(AppInfo appInfo){try{appInfoService.insertAppInfo(appInfo);return new AjaxResponse(true,"添加应用成功!");}catch (Exception e){return new AjaxResponse(false,"添加应用失败!");}}@PostMapping("/update")public AjaxResponse updateAppInfo(AppInfo appInfo){try{appInfoService.updateAppInfo(appInfo);return new AjaxResponse(true,"修改应用成功!");}catch (Exception e){return new AjaxResponse(false,"修改应用失败!");}}@PostMapping("/delete")public AjaxResponse deleteAppInfo(Long[] ids){if(ids!=null && ids.length>0){appInfoService.deleteAppInfoByIds(ids);return new AjaxResponse(true,"删除成功!");}return new AjaxResponse(false,"删除失败!");}@GetMapping("/table")public TableData<AppInfo> table(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "5") Integer limit) {TableData<AppInfo> tableData = new TableData<>();//page,limit,为分页的当前页和每面显示条数PageInfo<AppInfo> pageInfo = appInfoService.getAppInfoByPage(page, limit);// 设置tableData.setCount(pageInfo.getTotal());tableData.setData(pageInfo.getList());tableData.setMsg("查询成功!");return tableData;}
}
6.2.5 appinfo.html页面列表展示
复制一个customer.html文件,改名为appinfo.html,把页面中的cutomer全替换成appinfo
index.html页面中加多一个客户管理的访问标签
<li class="layui-nav-item"><a href="javascript:" onclick="openRight('/sys/appinfo.html')">应用管理</a>
</li>
把表格渲染的内容改为appinfo的信息
cols:[[{checkbox:true},{field: 'id', title: '编号', sort: true},{field: 'corpName', title: '公司名称'},{field: 'appName', title: '应用名称'},{field: 'appKey', title: 'appkey'},{field: 'appSecret', title: '秘钥'},{field: 'redirectUrl', title: '回调地址'},{field: 'linit', title: '限制访问次数'},{field: 'description', title: '描述'},{field: 'cusId', title: '客户ID'},{field: 'state', title: '状态',templet:function (data) { /*templet自定义列模板*/return (data.state==1)?'<span class="layui-badge layui-bg-green">有效</span>':'<span class="layui-badge layui-bg-red">无效</span>'}},{field:'right',title:'操作',toolbar:'#appinfo-appinfo-bar',width:150}
]]
6.2.6 编写获取客户列表的Controller方法
/**
* 查询所有客户列表,用于添加页面选择客户名称
*/
@RequestMapping("/tree")
public List<Customer> getAllCustomer(){return customerService.getAllCustomers();
}
6.2.7 添加应用
修改appinfo.html页面表单内容
<script type="text/html" id="appinfo-edit-layer"><form id="appinfo-edit-form" style="width: 80%" class="layui-form" lay-filter="appinfo-edit-form"><input type="hidden" name="id"><div class="layui-form-item"><label class="layui-form-label">应用名称</label><div class="layui-input-block"><input type="text" name="appName" required lay-verify="required" placeholder="请输入应用名称"autocomplete="off"class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">选择所属客户</label><div class="layui-input-block"><select name="cusId" id="cusId"></select></div></div><div class="layui-form-item"><label class="layui-form-label">appKey</label><div class="layui-input-block"><input type="text" name="appKey" required lay-verify="required" placeholder="请输入appKey"autocomplete="off"class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">密钥</label><div class="layui-input-block"><input type="text" name="appSecret" required lay-verify="required" placeholder="请输入密钥"autocomplete="off"class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">回调地址</label><div class="layui-input-block"><input type="text" name="redirectUrl" required lay-verify="required" placeholder="请输入回调地址"autocomplete="off"class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">调用次数</label><div class="layui-input-block"><input type="text" name="linit" required lay-verify="required" placeholder="请输入调用次数"autocomplete="off"class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">描述</label><div class="layui-input-block"><input type="text" name="description" required lay-verify="required" placeholder="请输入描述信息"autocomplete="off"class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">状态</label><div class="layui-input-block"><input type="radio" name="state" title="有效" value="1" checked/><input type="radio" name="state" title="无效" value="0"/></div></div></form>
</script>
openEditWindow()方法的success回调后添加填充下拉菜单的ajax异步请求
function openEditWindow(data) {/*弹出框*/layer.open({type: 1,content: $("#appinfo-edit-layer").html(),title:'编辑',area:['500px','400px'],btn:['提交','取消'],yes:function (index, layero) {/*确定按钮回调方法*/layer.load();/*加载层*/$.ajax({url:"/sys/appinfo/"+(data==null?'add':'update'),data:$("#appinfo-edit-form").serialize(),method:"POST",success:function(result){if(result.state){ /*状态是true*/table.reload('appinfo-table',{});/*表格重载,第二个参数为可选项*/layer.close(index); //如果设定了yes回调,需进行手工关闭}else{alert(result.message);}layer.closeAll("loading");/*loading为css样式*/}})},success:function (index, layero) {/*层弹出后的成功回调方法*/form.render();if(data!=null){/*语法:form.val('filter', object);用于给指定表单集合的元素赋值和取值。如果 object 参数存在,则为赋值;如果 object 参数不存在,则为取值。*/form.val("appinfo-edit-form",data);form.val("appinfo-edit-form",{"state":data.state+""});}/*发送异常请求后台,返回客户集合数据*/$.ajax({url:"/sys/customer/tree",type:"get",success:function(res){if(res){for(var i=0;i<res.length;i++){/*生成option并插入到select中,如果当前遍历的数据和应用的数据一样时,则自动选中*/if(data&&data.cusId&&data.cusId==res[i].id){$("#cusId").append("<option selected value="+res[i].id+">"+res[i].nickname+"</option>")}else{$("#cusId").append("<option value="+res[i].id+">"+res[i].nickname+"</option>")}}}form.render();/*刷新表单*/}})}})}
CustomerController中编写查询所有客户信息方法
/*** 查询所有客户列表,用于添加页面选择客户名称*/@RequestMapping("/tree")public List<Customer> getAllCustomer(){return customerService.getAllCustomers();}
AppInfoServiceImpl实现类的添加方法中需要给appinfo对象设置corpName属性的值,不然添加会报错,数据库中此列不允许为空
@Overridepublic int insertAppInfo(AppInfo appInfo) {Customer customer = customerMapper.getCustomerById(appInfo.getCusId());if (customer != null) {//设置客户名称,数据库中不能为空appInfo.setCorpName(customer.getNickname());}return appInfoMapper.insertAppInfo(appInfo);}
6.2.8 更新应用
ppInfoServiceImpl实现类的修改方法中需要给appinfo对象设置corpName属性的值,因为页面获取到的是cusId
@Overridepublic int updateAppInfo(AppInfo appInfo) {Customer customer = customerMapper.getCustomerById(appInfo.getCusId());if (customer != null) {//设置客户名称,数据库中不能为空appInfo.setCorpName(customer.getNickname());}return appInfoMapper.updateAppInfo(appInfo);}
6.2.9 按条件查询可参考客户管理的搜索
6.3 登录功能
6.3.1 创建login.html页面,并实现登录请求的js代码
login.html页面js代码
<script type="text/javascript">//JavaScript代码区域layui.use('form',function(){var form = layui.form;//检验密码form.verify({password:[ /^[\S]{6,12}$/, ,'密码必须6到12位,且不能出现空格']})//监听表单的提交事件form.on('submit(login)', function(data){console.log(data.elem) //被执行事件的元素DOM对象,一般为button对象console.log(data.form) //被执行提交的form对象,一般在存在form标签时才会返回console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}$.ajax({url:"/sys/adminUser/login",type:"post",data:data.field,success:function (result) {if(result.state){//登录成功window.location.href="index.html";}else{//登录失败$("#msg").html("登陆失败");}}})return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。});})
</script>
6.3.2 创建数据库表及AdminUser实体类
public class AdminUser {private Integer id;private String password;private String email;private String realName;private Integer status;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getRealName() {return realName;}public void setRealName(String realName) {this.realName = realName;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}
}
6.3.3 编写AdminUserController
实现登录认证的功能
@Controller
@RequestMapping("/sys/adminUser")
public class AdminUserController {@Autowiredprivate IAdminUserService adminUserService;@Autowiredprivate IMenuService menuService;@RequestMapping("/login")@ResponseBodypublic AjaxResponse checkLogin(String email, String password, HttpSession session){AdminUser adminUser = adminUserService.checkLogin(email,password);if(adminUser==null){return new AjaxResponse(false,"登录失败");}//登录成功session.setAttribute(Constacts.LOGIN_ADMIN_USER,adminUser);return new AjaxResponse(true,"登录成功");}
}
6.3.3 AdminUserService的编写
@Service
public class AdminUserServiceImpl implements IAdminUserService {@Autowiredprivate AdminUserMapper adminUserMapper;@Overridepublic AdminUser checkLogin(String email, String password) {AdminUser adminUser = adminUserMapper.checkLoginByEmail(email);if(adminUser==null || !adminUser.getPassword().equals(password)){return null;}return adminUser;}
}
6.3.4 AdminUserMapper编写
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qianfeng.openapi.web.master.mapper.AdminUserMapper"><resultMap id="userMap" type="com.qianfeng.openapi.web.master.pojo.AdminUser"><id property="id" column="ID"/><result property="status" column="STATUS"/><result property="realName" column="REAL_NAME"/><result property="email" column="EMAIL"/><result property="password" column="PASSWORD"/></resultMap><select id="checkLoginByEmail" resultType="com.qianfeng.openapi.web.master.pojo.AdminUser">select * from admin_user where EMAIL = #{email}</select>
</mapper>
6.4 实现不同用户登录看到不同菜单 RBAC 基于角色的权限访问控制
6.4.1 index.html页面的改造,展示菜单区域变成动态填充
<div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-filter="test" id="left-menu"></ul></div></div>
6.4.2 通过请求填充左侧菜单栏
填充菜单栏的js代码
<script>//JavaScript代码区域layui.use('element', function(){var element = layui.element;var str = "";$.ajax({url:"/sys/menu/side",type:"GET",success:function(json){/*遍历菜单集合信息*/$.each(json.result,function (i, obj) {str+='<li class="layui-nav-item layui-nav-itemed">';if(obj.type==1){str+='<a class="" href="javascript:;" οnclick="openRight(\''+obj.url+'\')" >'+obj.name+'</a>'}else{str+='<a class="" href="javascript:;">'+obj.name+'</a>'}if(obj.children.length>0){makeMenu(obj.children)}str+='</li>';})/*给 左侧导航区域填充数据*/$("#left-menu").html(str);}})function makeMenu(menuList) {str += '<dl class="layui-nav-child">';$.each(menuList,function (j, m) {str+='<dd>';if(m.type==1){str+='<a class="" href="javascript:;" οnclick="openRight(\''+m.url+'\')" >'+m.name+'</a>'}else{str+='<a class="" href="javascript:;">'+m.name+'</a>'}if(m.children.length>0){makeMenu(m.children)}str+='</dd>'})str+='</dl>';}});function openRight(url) {$(function(){$("#main").load(url);})}
</script>
6.4.3 创建数据库表及Menu实体类
Menu类
public class Menu {private Integer id;private String name;private Integer parentId;private String url;private String icon;private String perms;private Integer type;private Integer sort;private List<Menu> children = new ArrayList<>();//装二级菜单,页面展示需要public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getParentId() {return parentId;}public void setParentId(Integer parentId) {this.parentId = parentId;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getIcon() {return icon;}public void setIcon(String icon) {this.icon = icon;}public String getPerms() {return perms;}public void setPerms(String perms) {this.perms = perms;}public Integer getType() {return type;}public void setType(Integer type) {this.type = type;}public Integer getSort() {return sort;}public void setSort(Integer sort) {this.sort = sort;}public List<Menu> getChildren() {return children;}public void setChildren(List<Menu> children) {this.children = children;}
}
6.4.4 MenuController的编写
@RestController
@RequestMapping("/sys/menu")
public class MenuController {@Autowiredprivate IMenuService menuService;@RequestMapping("/side")public AjaxResponse side(HttpSession session, HttpServletResponse response) {//得到session中存储的对象AdminUser adminUser = (AdminUser) session.getAttribute(Constacts.LOGIN_ADMIN_USER);if (adminUser == null) {try {/*跳转到登录页面*/response.sendRedirect("/login.html");} catch (Exception e) {e.printStackTrace();}return new AjaxResponse(false, null, new ArrayList<>());}//获取用户所能查看的菜单List<Menu> list = menuService.getUserPerssion(adminUser.getId());return new AjaxResponse(true, null, list);}
6.4.5 MenuService 的编写
@Overridepublic List<Menu> getUserPerssion(Integer id) {//查询用户所能看到的菜单集合List<Menu> menus = menuMapper.getUserMenu(id);return makeMenuTree(menus);}
6.4.6 MenuMapper 的编写
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qianfeng.openapi.web.master.mapper.MenuMapper"><resultMap id="menuMap" type="com.qianfeng.openapi.web.master.pojo.Menu"><id property="id" column="ID"/><result property="name" column="NAME"/><result property="parentId" column="PARENT_ID"/><result property="url" column="URL"/><result property="icon" column="ICON"/><result property="perms" column="PERMS"/><result property="type" column="TYPE"/><result property="sort" column="SORT"/></resultMap><select id="getUserMenu" resultMap="menuMap">select m.* from menu minner join role_menu rmon m.ID = rm.MENU_IDINNER JOIN user_role uron ur.ROLE_ID = rm.ROLE_IDwhere ur.USER_ID = #{userId}</select></mapper>
6.4.7 makeMenuTree方法编写
返回一级菜单的集合,一级菜单中包括二级菜单的信息
private List<Menu> makeMenuTree(List<Menu> menus) {/*保存一级菜单*/List<Menu> firstMenu = new ArrayList<>();//定义一个map来存入menu对象Map<Integer,Menu> menuMap = new HashMap<>();for (Menu menu : menus) {//循环加菜单到map中menuMap.put(menu.getId(),menu);if(menu.getParentId() == null){//一级目录firstMenu.add(menu);}}for (Menu menu : menus) {if(menu.getType()!= Constacts.MENU_TYPE_BUTTON){//不是按钮if(menu.getParentId()!=null && menuMap.containsKey(menu.getParentId())){menuMap.get(menu.getParentId()).getChildren().add(menu);}}}return firstMenu;}
6.4.8 编写相应的常量
public class Constacts {public static final String LOGIN_ADMIN_USER ="login_admin_user";public static final int MENU_TYPE_DIR=0;public static final int MENU_TYPE_LINK=1;public static final int MENU_TYPE_BUTTON=2;
}
SSM项目——开放平台管理平台(开放源码)相关推荐
- 毕业设计-基于SSM框架大学教务管理平台项目开发实战教程(附源码)
文章目录 1.项目简介 2.项目收获 3.项目技术栈 4.测试账号 5.项目部分截图 6.常见问题 毕业设计-基于SSM框架大学教务管理平台项目实战教程-附源码 课程源码下载地址:https://do ...
- ssm毕设项目校外实习管理平台6tu82(java+VUE+Mybatis+Maven+Mysql+sprnig)
ssm毕设项目校外实习管理平台6tu82(java+VUE+Mybatis+Maven+Mysql+sprnig) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HB ...
- 基于SSM框架大学教务管理平台项目
基于SSM框架大学教务管理平台项目资料(源码和课程资料在课程附件中下载) https://edu.csdn.net/course/detail/31913 1.项目技术栈: 前端:HTML.CSS.J ...
- 基于SSM校园学术报告管理平台毕业设计文案及源码
基于SSM校园学术报告管理平台 SSM框架的毕业设计最新项目:基于SSM校园学术报告管理平台 目录: 项目介绍: 项目采用SSM框架+MySQL数据库做后台技术支持,JavaMaile完成邮件发送功能 ...
- 开源项目 ——API接口管理平台数据库原型设计(三)
开源项目 --API接口管理平台数据库原型设计(三) 背景 日常我们开发人员在开发一些常用的平台时都会用到各种各样的接口,而对于这些接口的有效管理都会成为我们的一些麻烦事,一些常见的接口管理平台我们使 ...
- ssm 远程监控linux,Wisenet SSM视频监控综合管理平台
Wisenet SSM视频监控综合管理平台是一款智能控制终端软件,而Wisenet SSM由Console Client程序和Core Server组成,也就是视频的监控和视频的保存功能. Wisen ...
- Java毕设项目中小学教务管理平台计算机(附源码+系统+数据库+LW)
Java毕设项目中小学教务管理平台计算机(附源码+系统+数据库+LW) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ E ...
- 基于SSM实现校友录管理平台
项目编号:BS-PT-019 后台开发技术:SSM框架 前端开发技术:Bootstrap+Jquery+Ajax 开发工具:IDEA / ECLIPSE 基于MAVEN开发 数据库:MYSQL5.7 ...
- (附源码)计算机毕业设计SSM智慧校园防疫管理平台
项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...
最新文章
- Netty 4.1 Getting Start (翻译) + Demo
- 实现在GET请求下调用WCF服务时传递对象(复合类型)参数
- 九个 Console 命令,让 js 调试更简单
- python爬虫入门教程-Python 爬虫介绍
- Windows下打包maven项目,编写bat脚本,dos命令在后台运行与关闭
- 快速排序 C++代码实现及其算法思想及时间复杂度分析及优化 恋上数据结构笔记
- HDU2015校赛 The Country List
- 对进程、线程和应用程序域的理解
- [2019上海网络赛F题]Rhyme scheme
- FFmpeg从视频中提取音频
- 电影爱好者福利,一些电影网站汇总
- 【Kay】Java多线程
- 用计算机写作文教学难点,《用计算机写作文》教学设计
- [ZT]毁人不倦的应试教育(2)
- 网吧组建及相关技术(无盘技术;VLAN;PacketTrace)
- Imazing2023免费版苹果手机iOS数据管理软件
- 前端大佬谈国产开源:VUE 的成功在于社区运营
- 光猫连接水星路由器显示服务器,水星mw300r路由器连接光猫的设置方法步骤
- [WriteUp]unctf-web-fuzz_md5
- The bean ‘XXX‘ could not be injected because it is a JDK dynamic proxy
热门文章
- 菲利普-泰特洛克的超预测速成课程(如何玩预测)
- PLC与继电器接触器控制系统对比
- 湖南大学计算机学硕毕业要求,湖南大学专业硕士学位授予基本要求(湖大研字[2010]6号)...
- 最近笔记本主板等硬件故障的一些经验教训
- 腾达ac9虚拟服务器,腾达AC9教你3招 胜过读100篇路由器攻略
- [luogu1402]酒店之王——最大流
- cisco 2901 配置拨号上网
- 关于java字符串+加号的理解
- 商业模式-名词解释10
- mysql 5.6 gtid mha_MySQL 5.6 GTID+MHA