开放平台(Open Platform) 在软件行业和网络中,开放平台是指软件系统通过公开其应用程序编程接口(API)或函数(function)来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源,而不需要更改该软件系统的源代码。在互联网时代,把网站的服务封装成一系列计算机易识别的数据接口开放出去,供第三方开发者使用,这种行为就叫做Open API,提供开放API的平台本身就被称为开放平台。
企业要调用别人的长板,通过API技术,互相调用、与行业形成链接。在借助他人长板的同时,也把自己的长板贡献给他人,就是互相赋能。
开放平台的作用简单地说就是通过第三方的力量来扩展自己的生态和能力,因为光凭自己做的软件并不能覆盖所有的场景,例如阿里、京东可以提供标准化的应用软件,可能满足于一些小的卖家使用,但是数百万形形色色的卖家对于个性化要求的软件,并不是一个公司的力量可以满足的,所以就把这些需求开放给众多的第三方开发者。
开放平台使用广泛、几乎所有的互联网公司都有自己的开放平台,知名的如京东的宙斯(JD Open Platform), 淘宝开放平台(Taobao Open Platform),百度的数据开放平台(https://open.baidu.com),大公司的开放平台都是一个完整的生态链,有很多第三方开发者(ISV),专门根据大的平台开放的接口,来开发出一些通用的软件,比如“E店宝”,依赖于淘宝、天猫、京东、拼多多等大型电商开放的接口,开发出的电商ERP的管理软件,通过这个 ERP 可以直接执行淘宝,京东等电商对外提供的功能,如查看订单,退货,上架产品等等
开放平台项目 |
---|
管理平台主要是对开放平台中的一些数据进行综合性管理,如客户管理,应用管理,充值管理,api 路由管理,网关参数管理,用户 Token 管理,日志搜索,权限管理,实现对服务的限流,熔断等动态配置,通过管理平台可以查看生成的数据,也可以通过管理平台将修改的数据同步到开放平台的网关系统中来实现实时更新功能
管理平台部分功能展示 |
---|
客户指的是注册了开放平台并通过平台来获取相应数据的人,如我们的淘宝账号可以通过淘宝的开放平台提供的 API 来实现对淘宝的一些功能的调用,如订单管理,商品管理等
客户主要包含的主要信息包括 用户名,密码,公司名称,账户余额,公司地址,账户状态等
客户管理主要是针对在开放平台上注册的用户进行管理, 可以对用户的账号密码,企业名称,账户余额等内容进行管理,并且可以代用户进行注册,编辑删除账户等操作
客户管理功能展示 |
---|
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
username | String | 用户名 |
password | String | 密码 |
nickname | String | 公司名称 |
address | String | 地址 |
money | int | 余额(毫) |
state | int | 状态 1 正常,0 停用 |
应用指的是客户在我们的平台创建的应用,一个客户可以创建多个应用,比如 抖音,今日头条,火山视频都是字节跳动的产品,它们都使用了微信分享和登陆这些开放功能,那么在微信的开放平台中,字节跳动就是一个客户,而抖音,今日头条都是字节跳动下面不同的应用,他们需要分别在微信开放平台创建出来才可以使用微信开放的功能
应用主要包含的主要信息为所属客户,应用名称,应用的 key,应用的秘钥(签名用),应用接收信息的回调 URL,应用对开放平台中接口的免费调用次数,应用描述等,关联功能客户管理
应用管理中主要包含创建应用,展示应用的相关信息,编辑修改应用,以及批量删除等操作,让管理人员可以随时通过对应用的信息修改来实现动态实时的限制
应用管理功能展示 |
---|
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
corpName | String | 关联企业名称,冗余减少查询 |
appName | String | 应用名称 |
appKey | String | 应用唯一标示 KEY |
AppSecret | String | 应用签名秘钥 |
redirectUrl | String | 应用回调用 URL |
linit | int | 免费接口日调用限制次数 |
description | String | 应用介绍 |
cusId | int | 关联客户 id |
state | int | 状态 |
在开放平台中,因为开放的服务的数量不确定,有的服务可能今年开放的,有的服务可能是明年新开发后开放的,有的服务可能过来一段时间后下线了,这一切都可能是随时变化的,因为如果每个服务都单独开发一套接口来让客户调用的话就变得非常繁琐,无法实现动态的调整,就像一个公司会有很多部门,每个部门都会招聘人,如果每个部门的招聘信息上面都写对应部门的人的话,就会变得很麻烦,我们需要在公司前台那里给每个部分留一个面试官,会浪费人员,最合适的办法是我们只要都留公司前台地址就行,我们只需要告诉前台每个部门的对接人信息就行,来面试的人员只要说明自己来面试哪个部门即可,前台会根据部门来找到对接人然后通知对接人即可,那么个前台就是统一的入口,她记录的对接人的信息就属于路由信息,我们只需要和前台沟通随时变更对接人信息即可,以后多了新部门只要和前台说新部门的信息即可
路由主要包含的主要信息为 路由的标识,对应的真正服务 id,对应服务的地址,描述信息,服务状态,幂等性,是否收费等
路由管理主要是对路由信息的添加,修改,启用,停用,幂等性状态修改, 是否收费等进行相关管理
路由管理功能展示 |
---|
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
gatewayApiName | String | 路由名称标识 |
insideApiUrl | String | 服务接口地址 |
serviceId | String | 服务名称 |
description | String | 介绍信息 |
state | int | 状态 1 有效,0 无效 |
idempotents | int | 幂等性 1 幂等 0 非幂等 |
needfee | int | 是否收费 1 收费 0 免费 |
我们的所有的服务在请求之前会要求我们必须传递某些名字的参数,就像我们去一家公司面试的时候不管面试的是什么部门都要带简历一样,这些参数我们成为系统参数
系统参数包含的主要信息是 参数名称,参数描述,参数状态
系统参数管理主要是针对我们网关中请求时候需要的系统参数进行管理,可以动态添加或者修改删除参数,修改后同步到网关中,网关即可实现动态参数校验的功能
系统参数管理功能展示 |
---|
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
name | String | 参数名 |
description | String | 参数介绍 |
state | int | 状态 1 启用,0 禁用 |
我们在访问功能的时候需要用登陆,单体项目的时候我们可以使用 session 来记录数据,但是在分布式系统中,session 共享比较复杂,所以我们会使用其他方式来记录这些状态,我们会在用户首次登陆的时候给他生成一个 token,下次用户带着 token 来我们进行校验即可
令牌在数据库中主要的信息为客户 id,token 内容,开始时间,过期时间等信息,关联客户信息
Token 管理主要是管理用户登录后生成的 token数据,修改有效期,删除等
Token 管理功能展示 |
---|
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
userId | int | 客户 id |
access_token | String | token 内容 |
startTime | DateTime | 开始时间 |
expireTime | DateTime | 结束时间 |
开放平台中部分接口的访问是需要收费的,因为用户需要先充值才可以使用
充值的数据信息主要是客户id,订单号,充值金额,日期,付费方式,状态等信息
充值管理主要是查看用户的充值记录,并且可以在自动充值出现问题的时候手动为用户充值
充值管理功能展示 |
---|
列名 | 类型 | 描述 |
---|---|---|
id | int | 主键 |
cusId | int | 客户 id |
createtime | DateTime | 创建订单时间 |
updateTime | DateTime | 更新时间 |
state | int | 状态,0未支付,1 已支付,2 已取消 |
paymenttype | int | 支付类型 0 银联,1 微信,2支付宝 |
我们的项目是一个管理平台,大部分的管理平台都是对内提供功能或者给用户提供部分可选功能,所以相对起来比较简单,大部分使用的是SSM单体架构,我们当前的项目也是采取的SSM架构
技术名称 | 针对的功能 | 介绍 | 版本 |
---|---|---|---|
SpringMVC | 控制层 | 主要用作于接收用户请求,封装参数,返回数据 | 5.1.x |
Spring | 对象管理 | 主要对我们项目需要的对象进行生命周期管理 | 5.1.x |
Mybatis | 持久层 | 主要是用于我们和数据库进行交互 | 3.5.x |
Quartz | 定时任务 | 比如定时备份数据 | 1.5.x |
LayUI | 前端展示 | 用于显示页面数据,传递数据到控制层 | 2.5.x |
工具名称 | 功能 | 介绍 |
---|---|---|
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,这个完全取决于我们的角度,当然如果不是前后端分离的项目,页面是我们写的,我们也可以按照需求先把页面写出来
项目相关依赖
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.1.6.RELEASEversion>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.1.10version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.10.2version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.5version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
dependencies>
在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
在resources文件夹下创建一个spring文件夹,存放spring相关文件,例如spring-context.xml
<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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qianfeng.openapi.web.master.service"/>
beans>
在resources文件夹下创建一个mybatis文件夹,存放mybatis主配置文件,例如mybatis-config.xml
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql"/>
plugin>
plugins>
configuration>
创建spring和mybatis整合的配置文件,spring-mybatis.xml
<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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:conf/jdbc.properties" />
<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 id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="mapperLocations" value="classpath:com/qianfeng/openapi/web/master/mapper/*.xml"/>
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
<property name="typeAliasesPackage" value="com.qianfeng.openapi.web.master.pojo"/>
bean>
<bean id="mapperScannerConfigurer9" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.qianfeng.openapi.web.master.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property>
bean>
beans>
创建spring和事务整合的配置文件,spring-transaction.xml
<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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<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>
在spring文件夹下创建springmvc的主配置文件,springmvc.xml
<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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.qianfeng.openapi.web.master.controller"/>
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
beans>
<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>contextConfigLocationparam-name>
<param-value>classpath:spring/spring-*.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
<servlet>
<servlet-name>mvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring/springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>mvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
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;
}
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文件
<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>
创建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 {
@Autowired
private CustomerMapper customerMapper;
@Override
public int insertCustomer(Customer customer) {
return customerMapper.insertCustomer(customer);
}
@Override
public int updateCustomer(Customer customer) {
//判断ID是否为空
if (customer.getId() != null) {
return customerMapper.updateCustomer(customer);
}else{
//给予提示
//TODO
}
return 0;
}
@Override
public int deleteCustomer(Long id) {
if (id != null) {
return customerMapper.deleteCustomer(id);
}else{
//给予提示
//TODO
}
return 0;
}
@Override
public Customer getCustomerById(Long id) {
if (id != null) {
return customerMapper.getCustomerById(id);
}else{
//给予提示
//TODO
}
return null;
}
@Override
public List<Customer> getAllCustomers() {
return customerMapper.getAllCustomers();
}
}
可以通过postman访问添加客户接口,并传递参数值
@RestController
@RequestMapping("/sys/customer")
public class CustomerController {
@Autowired
private ICustomerService customerService;
@PostMapping("/add")
public String add(Customer customer) {
customerService.insertCustomer(customer);
return "SUCCESS";
}
}
创建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>
导入已经画好的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)?'有效':'无效'
}},
{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类中的编码
@Override
public 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>
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 {
@Autowired
private 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,"修改失败!");
}
}
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>
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)?'有效':'无效'
}},
{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中的代码
@Override
public 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>
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;
}
}
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>
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 {
@Autowired
private AppInfoMapper appInfoMapper;
@Override
public int insertAppInfo(AppInfo appInfo) {
return appInfoMapper.insertAppInfo(appInfo);
}
@Override
public int updateAppInfo(AppInfo appInfo) {
return appInfoMapper.updateAppInfo(appInfo);
}
@Override
public int deleteAppInfoById(Long id) {
return appInfoMapper.deleteAppInfoById(id);
}
@Override
public int deleteAppInfoByIds(Long[] ids) {
return appInfoMapper.deleteAppInfoByIds(ids);
}
@Override
public AppInfo getAppInfoById(Long id) {
return appInfoMapper.getAppInfoById(id);
}
@Override
public List<AppInfo> getAppInfos() {
return appInfoMapper.getAppInfos();
}
@Override
public PageInfo<AppInfo> getAppInfoByPage(Integer page, Integer limit) {
PageHelper.startPage(page,limit);
List<AppInfo> appInfoList = appInfoMapper.getAppInfos();
return new PageInfo<>(appInfoList);
}
}
AppInfoController的编写
@RestController
@RequestMapping("/sys/appinfo")
public class AppInfoController {
@Autowired
private 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;
}
}
复制一个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)?'有效':'无效'
}},
{field:'right',title:'操作',toolbar:'#appinfo-appinfo-bar',width:150}
]]
/**
* 查询所有客户列表,用于添加页面选择客户名称
*/
@RequestMapping("/tree")
public List<Customer> getAllCustomer(){
return customerService.getAllCustomers();
}
修改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("res[i].id+">"+res[i].nickname+"")
}else{
$("#cusId").append("res[i].id+">"+res[i].nickname+"")
}
}
}
form.render();/*刷新表单*/
}
})
}
})
}
CustomerController中编写查询所有客户信息方法
/**
* 查询所有客户列表,用于添加页面选择客户名称
*/
@RequestMapping("/tree")
public List<Customer> getAllCustomer(){
return customerService.getAllCustomers();
}
AppInfoServiceImpl实现类的添加方法中需要给appinfo对象设置corpName属性的值,不然添加会报错,数据库中此列不允许为空
@Override
public int insertAppInfo(AppInfo appInfo) {
Customer customer = customerMapper.getCustomerById(appInfo.getCusId());
if (customer != null) {
//设置客户名称,数据库中不能为空
appInfo.setCorpName(customer.getNickname());
}
return appInfoMapper.insertAppInfo(appInfo);
}
ppInfoServiceImpl实现类的修改方法中需要给appinfo对象设置corpName属性的值,因为页面获取到的是cusId
@Override
public int updateAppInfo(AppInfo appInfo) {
Customer customer = customerMapper.getCustomerById(appInfo.getCusId());
if (customer != null) {
//设置客户名称,数据库中不能为空
appInfo.setCorpName(customer.getNickname());
}
return appInfoMapper.updateAppInfo(appInfo);
}
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>
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;
}
}
实现登录认证的功能
@Controller
@RequestMapping("/sys/adminUser")
public class AdminUserController {
@Autowired
private IAdminUserService adminUserService;
@Autowired
private IMenuService menuService;
@RequestMapping("/login")
@ResponseBody
public 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,"登录成功");
}
}
@Service
public class AdminUserServiceImpl implements IAdminUserService {
@Autowired
private AdminUserMapper adminUserMapper;
@Override
public AdminUser checkLogin(String email, String password) {
AdminUser adminUser = adminUserMapper.checkLoginByEmail(email);
if(adminUser==null || !adminUser.getPassword().equals(password)){
return null;
}
return adminUser;
}
}
<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>
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<ul class="layui-nav layui-nav-tree" lay-filter="test" id="left-menu">
ul>
div>
div>
填充菜单栏的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+='' ;
if(obj.type==1){
str+='+obj.url+'\')" >'+obj.name+''
}else{
str+=''+obj.name+''
}
if(obj.children.length>0){
makeMenu(obj.children)
}
str+='';
})
/*给 左侧导航区域填充数据*/
$("#left-menu").html(str);
}
})
function makeMenu(menuList) {
str += ''
;
$.each(menuList,function (j, m) {
str+='' ;
if(m.type==1){
str+='+m.url+'\')" >'+m.name+''
}else{
str+=''+m.name+''
}
if(m.children.length>0){
makeMenu(m.children)
}
str+=''
})
str+='';
}
});
function openRight(url) {
$(function(){
$("#main").load(url);
})
}
</script>
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;
}
}
@RestController
@RequestMapping("/sys/menu")
public class MenuController {
@Autowired
private 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);
}
@Override
public List<Menu> getUserPerssion(Integer id) {
//查询用户所能看到的菜单集合
List<Menu> menus = menuMapper.getUserMenu(id);
return makeMenuTree(menus);
}
<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 m
inner join role_menu rm
on m.ID = rm.MENU_ID
INNER JOIN user_role ur
on ur.ROLE_ID = rm.ROLE_ID
where ur.USER_ID = #{userId}
select>
mapper>
返回一级菜单的集合,一级菜单中包括二级菜单的信息
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;
}
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;
}