SSM项目——开放平台管理平台(开放源码)

l开放平台 logo

文章目录

一、 引言


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 可以直接执行淘宝,京东等电商对外提供的功能,如查看订单,退货,上架产品等等

开放平台项目
image-20200406192830180

二 、开放平台之管理平台


2.1 管理平台介绍

管理平台主要是对开放平台中的一些数据进行综合性管理,如客户管理,应用管理,充值管理,api 路由管理,网关参数管理,用户 Token 管理,日志搜索,权限管理,实现对服务的限流,熔断等动态配置,通过管理平台可以查看生成的数据,也可以通过管理平台将修改的数据同步到开放平台的网关系统中来实现实时更新功能

管理平台部分功能展示
image-20200406201435552

2.2 客户管理

2.2.1 介绍
  • 客户指的是注册了开放平台并通过平台来获取相应数据的人,如我们的淘宝账号可以通过淘宝的开放平台提供的 API 来实现对淘宝的一些功能的调用,如订单管理,商品管理等

  • 客户主要包含的主要信息包括 用户名,密码,公司名称,账户余额,公司地址,账户状态

  • 客户管理主要是针对在开放平台上注册的用户进行管理, 可以对用户的账号密码,企业名称,账户余额等内容进行管理,并且可以代用户进行注册,编辑删除账户等操作

2.2.2 功能展示
客户管理功能展示
image-20200406221508173
2.2.2 数据库结构
列名 类型 描述
id int 主键
username String 用户名
password String 密码
nickname String 公司名称
address String 地址
money int 余额(毫)
state int 状态 1 正常,0 停用

2.3 应用管理

2.3.1 介绍
2.3.2 功能展示
应用管理功能展示
image-20200406223821508
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 功能展示
路由管理功能展示
image-20200406201435552
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 功能展示
系统参数管理功能展示
image-20200407011654545
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 管理功能展示
image-20200407161548386
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 功能展示
充值管理功能展示
image-20200409003804117
2.7.3 数据库结构
列名 类型 描述
id int 主键
cusId 客户 id 客户 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/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">

    <!--扫描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/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" />

    <!--与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/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">


    <!-- 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/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">

    <!--扫描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 {
    
    

    @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();
    }
}
6.1.9 创建CustomerController并测试Controller添加客户信息

可以通过postman访问添加客户接口,并传递参数值

@RestController
@RequestMapping("/sys/customer")
public class CustomerController {

    @Autowired
    private 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类中的编码

 @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>
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 {
    
    

    @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,"修改失败!");
        }
    }
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中的代码

  @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>

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 {
    
    

    @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);
    }
}

6.2.4 应用管理的controller

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;
    }
}
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属性的值,不然添加会报错,数据库中此列不允许为空

 @Override
    public 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

  @Override
    public 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 {
    
    

    @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,"登录成功");
    }
}
6.3.3 AdminUserService的编写
@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;
    }
}
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 {
    
    

    @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);
    }
6.4.5 MenuService 的编写
   @Override
    public 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 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>
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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43556773/article/details/109587376