├── imgs ├── login.png ├── shuju.png ├── dingdan.png ├── fenlei.png ├── fenlei1.png ├── jianyan.png ├── shibie.png ├── yonghu.png ├── yonghu1.png ├── quanxian.png ├── quanxian1.png └── shitilei.png ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── src ├── main │ ├── java │ │ └── cn │ │ │ └── blue │ │ │ └── mall │ │ │ ├── bean │ │ │ ├── RolesPowers.java │ │ │ ├── Userlist.java │ │ │ ├── FaceInfo.java │ │ │ ├── Roles.java │ │ │ ├── GoodsInfo.java │ │ │ ├── Powers.java │ │ │ └── UserInfo.java │ │ │ ├── face │ │ │ ├── Race.java │ │ │ ├── Glasses.java │ │ │ ├── Emotion.java │ │ │ ├── Face_shape.java │ │ │ ├── Gender.java │ │ │ ├── Expression.java │ │ │ ├── Face_type.java │ │ │ ├── Eye_status.java │ │ │ ├── Angle.java │ │ │ ├── Quality.java │ │ │ ├── Location.java │ │ │ ├── JsonRootBean.java │ │ │ ├── Occlusion.java │ │ │ ├── Result.java │ │ │ └── Face_list.java │ │ │ ├── MallApplication.java │ │ │ ├── service │ │ │ ├── GoodsService.java │ │ │ ├── PowersService.java │ │ │ ├── impl │ │ │ │ ├── GoodsServiceImpl.java │ │ │ │ ├── PowersServiceImpl.java │ │ │ │ ├── UserInfoServiceImpl.java │ │ │ │ ├── RolesServiceImpl.java │ │ │ │ └── AuthServiceImpl.java │ │ │ ├── UserInfoService.java │ │ │ └── RolesService.java │ │ │ ├── mapper │ │ │ ├── GoodsMapper.java │ │ │ ├── UserInfoMapper.java │ │ │ ├── PowersMapper.java │ │ │ └── RolesMapper.java │ │ │ ├── config │ │ │ ├── CorsConfig.java │ │ │ ├── SecurityConfig.java │ │ │ └── TomcatConfig.java │ │ │ ├── utils │ │ │ ├── GsonUtils.java │ │ │ ├── Result.java │ │ │ ├── FaceGetList.java │ │ │ ├── FaceMatch.java │ │ │ ├── FaceSearch.java │ │ │ ├── FaceAdd.java │ │ │ ├── FaceDetect.java │ │ │ ├── FileUtil.java │ │ │ ├── Base64Util.java │ │ │ └── HttpUtil.java │ │ │ ├── consts │ │ │ └── FaceConst.java │ │ │ └── controller │ │ │ ├── PowersController.java │ │ │ ├── GoodsController.java │ │ │ ├── UserInfoController.java │ │ │ ├── RolesController.java │ │ │ └── FaceController.java │ └── resources │ │ ├── application.yml │ │ └── mapper │ │ ├── GoodsMapper.xml │ │ ├── RolesMapper.xml │ │ ├── UserInfoMapper.xml │ │ └── PowersMapper.xml └── test │ └── java │ └── cn │ └── blue │ └── mall │ ├── MallApplicationTests.java │ ├── service │ └── impl │ │ └── AuthServiceImplTest.java │ └── utils │ ├── FaceAddTest.java │ ├── FaceSearchTest.java │ └── FaceDetectTest.java ├── .gitignore ├── 人脸识别返回参数示例.json ├── pom.xml ├── mvnw.cmd ├── mvnw ├── mall_vue.sql ├── README.md └── api接口文档.md /imgs/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/login.png -------------------------------------------------------------------------------- /imgs/shuju.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/shuju.png -------------------------------------------------------------------------------- /imgs/dingdan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/dingdan.png -------------------------------------------------------------------------------- /imgs/fenlei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/fenlei.png -------------------------------------------------------------------------------- /imgs/fenlei1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/fenlei1.png -------------------------------------------------------------------------------- /imgs/jianyan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/jianyan.png -------------------------------------------------------------------------------- /imgs/shibie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/shibie.png -------------------------------------------------------------------------------- /imgs/yonghu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/yonghu.png -------------------------------------------------------------------------------- /imgs/yonghu1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/yonghu1.png -------------------------------------------------------------------------------- /imgs/quanxian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/quanxian.png -------------------------------------------------------------------------------- /imgs/quanxian1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/quanxian1.png -------------------------------------------------------------------------------- /imgs/shitilei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/imgs/shitilei.png -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderBleu/springboot-vue/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/RolesPowers.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Blue 7 | * @date 2020/3/13 8 | **/ 9 | @Data 10 | public class RolesPowers { 11 | private Integer rolesId; 12 | private Integer powersId; 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/cn/blue/mall/MallApplicationTests.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class MallApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Race.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Race { 16 | 17 | private String type; 18 | private double probability; 19 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Glasses.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Glasses { 16 | 17 | private String type; 18 | private double probability; 19 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Emotion.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Emotion { 16 | 17 | private String type; 18 | private double probability; 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Face_shape.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Face_shape { 16 | 17 | private String type; 18 | private double probability; 19 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Gender.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Gender { 16 | 17 | private String type; 18 | private double probability; 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Expression.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Expression { 16 | 17 | private String type; 18 | private double probability; 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Face_type.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Face_type { 16 | 17 | private String type; 18 | private double probability; 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Eye_status.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Eye_status { 16 | 17 | private double left_eye; 18 | private double right_eye; 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Angle.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Angle { 16 | 17 | private double yaw; 18 | private double pitch; 19 | private double roll; 20 | 21 | } -------------------------------------------------------------------------------- /src/test/java/cn/blue/mall/service/impl/AuthServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service.impl; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import javax.annotation.Resource; 6 | 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | class AuthServiceImplTest { 10 | 11 | @Test 12 | void getAuth() { 13 | System.out.println(AuthServiceImpl.getAuth()); 14 | } 15 | 16 | @Test 17 | void testGetAuth() { 18 | } 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/Userlist.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Blue 7 | * @date 2020/5/4 8 | * 人脸识别后的用户列表信息 9 | **/ 10 | @Data 11 | public class Userlist { 12 | /** 13 | * 人脸库id 14 | */ 15 | private String group_id; 16 | /** 17 | * 图片的id 18 | */ 19 | private String user_id; 20 | 21 | private String user_info; 22 | /** 23 | * 比对分数 24 | */ 25 | private double score; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Quality.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Quality { 16 | 17 | private Occlusion occlusion; 18 | private double blur; 19 | private double illumination; 20 | private double completeness; 21 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/MallApplication.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @MapperScan("cn.blue.mall.mapper") 9 | public class MallApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(MallApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Location.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Location { 16 | 17 | private double left; 18 | private double top; 19 | private Integer width; 20 | private Integer height; 21 | private double rotation; 22 | 23 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/JsonRootBean.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class JsonRootBean { 16 | 17 | private Integer error_code; 18 | private String error_msg; 19 | private long log_id; 20 | private long timestamp; 21 | private Integer cached; 22 | private Result result; 23 | 24 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/FaceInfo.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import cn.blue.mall.face.Result; 4 | import lombok.Data; 5 | 6 | /** 7 | * @author Blue 8 | * @date 2020/5/4 9 | * 人脸识别反馈信息 10 | **/ 11 | @Data 12 | public class FaceInfo { 13 | /** 14 | * 状态码 0 15 | */ 16 | private Integer error_code; 17 | /** 18 | * 成功返回 SUCCESS 19 | */ 20 | private String error_msg; 21 | 22 | private long log_id; 23 | 24 | private long timestamp; 25 | 26 | private double cached; 27 | 28 | private Result result; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Occlusion.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Occlusion { 16 | 17 | private double left_eye; 18 | private double right_eye; 19 | private double nose; 20 | private double mouth; 21 | private double left_cheek; 22 | private double right_cheek; 23 | private double chin_contour; 24 | 25 | } -------------------------------------------------------------------------------- /src/test/java/cn/blue/mall/utils/FaceAddTest.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import cn.blue.mall.bean.FaceInfo; 4 | import lombok.SneakyThrows; 5 | import org.junit.jupiter.api.Test; 6 | 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | class FaceAddTest { 10 | 11 | @SneakyThrows 12 | @Test 13 | void faceAdd() { 14 | String encode = Base64Util.encode(FileUtil.readFileByBytes("D:\\pythonDemo\\7.jpg")); 15 | System.out.println("encode:" + encode); 16 | String resultJson = FaceAdd.faceAdd(encode); 17 | System.out.println(resultJson); 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/Roles.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Blue 9 | * @date 2020/3/10 10 | **/ 11 | @Data 12 | public class Roles { 13 | /** 14 | * 权限id 15 | */ 16 | private Integer id; 17 | /** 18 | * 角色名称 19 | */ 20 | private String roleName; 21 | /** 22 | * 角色描述 23 | */ 24 | private String roleDesc; 25 | /** 26 | * 一级权限 27 | */ 28 | private List roles; 29 | 30 | /** 31 | * 一个角色可以拥有多个权限 32 | */ 33 | private List powers; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/GoodsService.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service; 2 | 3 | import cn.blue.mall.bean.GoodsInfo; 4 | 5 | import java.util.List; 6 | 7 | public interface GoodsService { 8 | 9 | /** 10 | * 查找商品列表 11 | * @param goodsInfo 商品信息 12 | * @return 商品列表 13 | */ 14 | List findAll(GoodsInfo goodsInfo); 15 | 16 | /** 17 | * 根据商品id修改分类信息 18 | * @param goodsInfo 商品信息 19 | */ 20 | void updateById(GoodsInfo goodsInfo); 21 | 22 | /** 23 | * 根据父级id来添加子分类 24 | * @param goodsInfo 分类信息 25 | */ 26 | void addCatByPId(GoodsInfo goodsInfo); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/GoodsInfo.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Blue 9 | * @date 2020/3/15 10 | **/ 11 | @Data 12 | public class GoodsInfo { 13 | private Integer id; 14 | /** 15 | * 商品名字 16 | */ 17 | private String catName; 18 | /** 19 | * 父级id 20 | */ 21 | private Integer catPid; 22 | /** 23 | * 是否有效 24 | */ 25 | private Integer catDeleted; 26 | /** 27 | * 几级分类 28 | */ 29 | private Integer catLevel; 30 | /** 31 | * 下级分类信息 32 | */ 33 | private List children; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Result.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | import cn.blue.mall.bean.Userlist; 6 | import lombok.Data; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Auto-generated: 2020-05-04 17:32:26 12 | * 13 | * @author bejson.com (i@bejson.com) 14 | * @website http://www.bejson.com/java2pojo/ 15 | */ 16 | @Data 17 | public class Result { 18 | 19 | private Integer face_num; 20 | private List face_list; 21 | /** 22 | * face_token值 23 | */ 24 | private String face_token; 25 | /** 26 | * 查询的用户列表信息 27 | */ 28 | private List user_list; 29 | } -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | 4 | spring: 5 | datasource: 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | url: jdbc:mysql://localhost:3306/mall_vue?serverTimezone=GMT%2b8 8 | username: root 9 | password: root 10 | 11 | thymeleaf: 12 | cache: false 13 | 14 | servlet: 15 | multipart: 16 | max-file-size: 1000MB 17 | max-request-size: 1000MB 18 | 19 | mybatis: 20 | mapper-locations: classpath:/mapper/*.xml 21 | configuration: 22 | map-underscore-to-camel-case: true 23 | 24 | type-aliases-package: cn.blue.mall.bean 25 | 26 | logging: 27 | level: 28 | cn.blue: trace 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/test/java/cn/blue/mall/utils/FaceSearchTest.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import cn.blue.mall.bean.FaceInfo; 4 | import cn.blue.mall.face.Face_list; 5 | import cn.blue.mall.face.JsonRootBean; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.List; 9 | 10 | import static org.junit.jupiter.api.Assertions.*; 11 | 12 | class FaceSearchTest { 13 | 14 | @Test 15 | void faceSearch() { 16 | // 上传的图片不宜太大了,不然不好处理。 17 | String resultJson = FaceSearch.faceSearch("D:\\pythonDemo\\8.jpg"); 18 | FaceInfo faceInfo = GsonUtils.fromJson(resultJson, FaceInfo.class); 19 | System.err.println("人脸搜索:" + faceInfo.getResult().getUser_list().get(0).getScore()); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/mapper/GoodsMapper.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.mapper; 2 | 3 | import cn.blue.mall.bean.GoodsInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | import java.util.List; 7 | 8 | @Mapper 9 | public interface GoodsMapper { 10 | /** 11 | * 查找商品列表 12 | * 13 | * @param goodsInfo 商品信息 14 | * @return 商品列表 15 | */ 16 | List findAll(GoodsInfo goodsInfo); 17 | 18 | /** 19 | * 根据商品id修改分类信息 20 | * 21 | * @param goodsInfo 商品信息 22 | */ 23 | void updateById(GoodsInfo goodsInfo); 24 | 25 | /** 26 | * 根据父级id来添加子分类 27 | * 28 | * @param goodsInfo 分类信息 29 | */ 30 | void addCatByPId(GoodsInfo goodsInfo); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/PowersService.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service; 2 | 3 | import cn.blue.mall.bean.Powers; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 用户信息的服务层 9 | */ 10 | public interface PowersService { 11 | /** 12 | * 查询用户所有列表信息 13 | * @return powers 14 | */ 15 | public List findAll(Powers powers); 16 | /** 17 | * 查询用户所有列表信息 18 | * @return powers 19 | */ 20 | List findPowersTree(); 21 | 22 | /** 23 | * 查找是否是三级权限 24 | * @param id 25 | * @return 26 | */ 27 | Powers findThirdGrade(Integer powersId); 28 | 29 | /** 30 | * 根据角色的id设置一级权限的pid 31 | * @param id 角色的id 32 | */ 33 | boolean setPidByRolesId(Integer id); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/Powers.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Blue 9 | * @date 2020/3/10 10 | **/ 11 | @Data 12 | public class Powers { 13 | /** 14 | * 权限id 15 | */ 16 | private Integer id; 17 | /** 18 | * 权限名称 19 | */ 20 | private String authName; 21 | /** 22 | * 权限等级 23 | */ 24 | private Integer grade; 25 | /** 26 | * 父权限id 27 | */ 28 | private Integer pid; 29 | /** 30 | * 权限路径 31 | */ 32 | private String path; 33 | /** 34 | * 二级权限 35 | */ 36 | private List children; 37 | 38 | private boolean isHaveChildren; 39 | 40 | private List rp; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/config/CorsConfig.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 6 | 7 | /** 8 | * @author Blue 9 | * @date 2020/2/11 10 | * 解决跨域的问题 11 | **/ 12 | @Configuration 13 | public class CorsConfig implements WebMvcConfigurer { 14 | 15 | @Override 16 | public void addCorsMappings(CorsRegistry registry) { 17 | registry.addMapping("/**") 18 | .allowedOrigins("*") 19 | .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") 20 | .allowCredentials(true) 21 | .maxAge(3600) 22 | .allowedHeaders("*"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/face/Face_list.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2020 bejson.com 3 | */ 4 | package cn.blue.mall.face; 5 | 6 | import lombok.Data; 7 | 8 | /** 9 | * Auto-generated: 2020-05-04 17:32:26 10 | * 11 | * @author bejson.com (i@bejson.com) 12 | * @website http://www.bejson.com/java2pojo/ 13 | */ 14 | @Data 15 | public class Face_list { 16 | 17 | private String face_token; 18 | private Location location; 19 | private double face_probability; 20 | private Angle angle; 21 | private Integer age; 22 | private double beauty; 23 | private Expression expression; 24 | private Face_shape face_shape; 25 | private Gender gender; 26 | private Glasses glasses; 27 | private Race race; 28 | private Quality quality; 29 | private Eye_status eye_status; 30 | private Emotion emotion; 31 | private Face_type face_type; 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/bean/UserInfo.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.bean; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Blue 7 | * @date 2020/3/5 8 | **/ 9 | @Data 10 | public class UserInfo { 11 | /** 12 | * 用户表主键 13 | */ 14 | private String id; 15 | /** 16 | * 用户姓名 17 | */ 18 | private String name; 19 | /** 20 | * 用户密码 21 | */ 22 | private String password; 23 | /** 24 | * 用户邮箱 25 | */ 26 | private String email; 27 | /** 28 | * 用户电话 29 | */ 30 | private String telephone; 31 | /** 32 | * 用户角色id:0超管,1管理员,2销售 33 | */ 34 | private Integer role; 35 | /** 36 | * 用户状态:0正常,1删除 37 | */ 38 | private Integer status; 39 | 40 | /** 41 | * 分配的角色 42 | */ 43 | private Roles roles; 44 | /** 45 | * 46 | */ 47 | private FaceInfo faceInfo; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/GsonUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Baidu, Inc. All Rights Reserved. 3 | */ 4 | package cn.blue.mall.utils; 5 | 6 | import com.google.gson.Gson; 7 | import com.google.gson.GsonBuilder; 8 | import com.google.gson.JsonParseException; 9 | 10 | import java.lang.reflect.Type; 11 | 12 | /** 13 | * Json工具类. 14 | * @author Blue 15 | */ 16 | public class GsonUtils { 17 | private static Gson gson = new GsonBuilder().create(); 18 | 19 | public static String toJson(Object value) { 20 | return gson.toJson(value); 21 | } 22 | 23 | public static T fromJson(String json, Class classOfT) throws JsonParseException { 24 | return gson.fromJson(json, classOfT); 25 | } 26 | 27 | public static T fromJson(String json, Type typeOfT) throws JsonParseException { 28 | return (T) gson.fromJson(json, typeOfT); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/consts/FaceConst.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.consts; 2 | 3 | /** 4 | * @author Blue 5 | * @date 2020/5/4 6 | * 人脸识别常量 7 | **/ 8 | public interface FaceConst { 9 | 10 | /** 11 | * 路径前缀 12 | */ 13 | String PATH_PRE = "D:\\Temp\\"; 14 | 15 | /** 16 | * 路径后缀 17 | */ 18 | String PATH_SUF = "_face.jpg"; 19 | 20 | /** 21 | * 人脸比对的成绩 22 | */ 23 | Integer SCORE = 80; 24 | 25 | /** 26 | * 人脸比对的成绩 27 | */ 28 | String NO_FACE = "pic not has face"; 29 | 30 | /** 31 | * 人脸比对的成绩 32 | */ 33 | String ERROR_MSG = "SUCCESS"; 34 | 35 | /** 36 | * 百度云应用的AK 37 | */ 38 | String CLIENT_ID = "Pr9pmCNIHsozqlqAOT18f3S7"; 39 | 40 | /** 41 | * 百度云应用的SK 42 | */ 43 | String CLIENT_SECRET = "2FhMGEuyREsy5vy7vC55GaNV8TTVfZfv"; 44 | 45 | /** 46 | * 人脸库 47 | */ 48 | String GROUP_ID = "mall_vue"; 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/impl/GoodsServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service.impl; 2 | 3 | import cn.blue.mall.bean.GoodsInfo; 4 | import cn.blue.mall.mapper.GoodsMapper; 5 | import cn.blue.mall.service.GoodsService; 6 | import org.springframework.stereotype.Service; 7 | 8 | import javax.annotation.Resource; 9 | import java.util.List; 10 | 11 | /** 12 | * @author Blue 13 | * @date 2020/3/15 14 | **/ 15 | @Service("goodsService") 16 | public class GoodsServiceImpl implements GoodsService { 17 | @Resource 18 | private GoodsMapper goodsMapper; 19 | 20 | @Override 21 | public List findAll(GoodsInfo goodsInfo) { 22 | return goodsMapper.findAll(goodsInfo); 23 | } 24 | 25 | @Override 26 | public void updateById(GoodsInfo goodsInfo) { 27 | goodsMapper.updateById(goodsInfo); 28 | } 29 | 30 | @Override 31 | public void addCatByPId(GoodsInfo goodsInfo) { 32 | goodsMapper.addCatByPId(goodsInfo); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/UserInfoService.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service; 2 | 3 | import cn.blue.mall.bean.UserInfo; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 用户信息的服务层 10 | */ 11 | public interface UserInfoService { 12 | /** 13 | * 查询用户所有列表信息 14 | * @return UserInfo集合 15 | */ 16 | public List findAll(UserInfo userInfo); 17 | 18 | /** 19 | * 根据用户id修改用户状态 20 | * @param status 用户状态 21 | * @param id 用户id 22 | * @return 是否成功 23 | */ 24 | boolean updateStatusById(UserInfo userInfo); 25 | 26 | /** 27 | * 新增用户 28 | * @param userInfo 用户信息 29 | * @return 是否添加成功 30 | */ 31 | boolean addUser(UserInfo userInfo); 32 | 33 | /** 34 | * 新增用户 35 | * @param userInfo 用户信息 36 | * @return 是否修改成功 37 | */ 38 | boolean updateUserById(UserInfo userInfo); 39 | 40 | /** 41 | * 新增用户 42 | * @param id 用户id 43 | * @return 是否删除成功 44 | */ 45 | boolean deleteById(String id); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/RolesService.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service; 2 | 3 | import cn.blue.mall.bean.Powers; 4 | import cn.blue.mall.bean.Roles; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 用户信息的服务层 10 | */ 11 | public interface RolesService { 12 | /** 13 | * 查询角色所有列表信息 14 | * @return roles 15 | */ 16 | public List findAll(Roles roles); 17 | 18 | /** 19 | * 查询角色下权限列表信息 20 | * @return roles 21 | */ 22 | public List findAllPowers(Roles roles); 23 | 24 | /** 25 | * 根据角色id来查权限树 26 | * @param rolesId 角色id 27 | * @return 权限树 28 | */ 29 | List findTreeByRolesId(Integer rolesId); 30 | 31 | /** 32 | * 根据用户id来更新中间表信息,即更新权限的分配 33 | * @param ids 权限ids 34 | * @param rolesId 角色id 35 | * @return 是否成功 36 | */ 37 | boolean updateTreeByIds(Integer[] ids, Integer rolesId); 38 | 39 | List findExpandTree(); 40 | 41 | /** 42 | * 新增角色 43 | * @param roles 角色信息 44 | * @return 是否成功 45 | */ 46 | boolean addNewRole(Roles roles); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/mapper/UserInfoMapper.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.mapper; 2 | 3 | import cn.blue.mall.bean.UserInfo; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface UserInfoMapper { 11 | /** 12 | * 查询用户所有列表信息 13 | * 14 | * @return UserInfo集合 15 | */ 16 | public List findAll(UserInfo userInfo); 17 | 18 | /** 19 | * 根据用户id修改用户状态 20 | * 21 | * @param userInfo 用户id 用户状态 22 | * @return 受影响行数 23 | */ 24 | int updateStatusById(@Param("userInfo") UserInfo userInfo); 25 | 26 | /** 27 | * 新增用户 28 | * 29 | * @param userInfo 用户信息 30 | * @return 受影响行数 31 | */ 32 | int addUser(UserInfo userInfo); 33 | 34 | /** 35 | * 新增用户 36 | * 37 | * @param userInfo 用户信息 38 | * @return 受影响行数 39 | */ 40 | int updateUserById(UserInfo userInfo); 41 | 42 | /** 43 | * 新增用户 44 | * @param id 用户id 45 | * @return 是否删除成功 46 | */ 47 | int deleteById(String id); 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | //package cn.blue.mall.config; 2 | // 3 | //import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration; 4 | //import org.springframework.context.annotation.Configuration; 5 | //import org.springframework.security.config.annotation.web.WebSecurityConfigurer; 6 | //import org.springframework.security.config.annotation.web.builders.WebSecurity; 7 | //import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | //import org.springframework.stereotype.Component; 9 | //import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | // 11 | ///** 12 | // * @author Blue 13 | // * @date 2020/3/18 14 | // **/ 15 | //@Configuration 16 | //public class SecurityConfig extends WebSecurityConfigurerAdapter { 17 | // 18 | // @Override 19 | // public void configure(WebSecurity web) throws Exception { 20 | // web.ignoring().antMatchers("/login","/Login", "/img/**","/fonts/**", 21 | // "/css/**", "/index.html", "/favicon.ico", "/*.xml", "*.xml"); 22 | // } 23 | //} 24 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/Result.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * 封装返回的ajax值 7 | * 8 | * @author Blue 9 | * 10 | */ 11 | public class Result extends HashMap { 12 | 13 | /** 14 | * 15 | */ 16 | private static final long serialVersionUID = 1L; 17 | 18 | private Result() { 19 | } 20 | 21 | public static Result success() { 22 | return new Result().setCode(200); 23 | } 24 | 25 | public static Result error(int code) { 26 | return new Result().setCode(code); 27 | } 28 | 29 | public Result add(String key, Object value) { 30 | this.put(key, value); 31 | return this; 32 | } 33 | 34 | public Result setCode(int code) { 35 | this.put("code", code); 36 | return this; 37 | } 38 | 39 | public int getCode() { 40 | return this.getValue("code"); 41 | } 42 | 43 | public Result setMsg(String msg) { 44 | this.put("msg", msg); 45 | return this; 46 | } 47 | 48 | public String getMsg() { 49 | return this.getValue("msg"); 50 | } 51 | 52 | public T getValue(String key) { 53 | return (T) this.get(key); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/config/TomcatConfig.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.config; 2 | 3 | /** 4 | * @author Blue 5 | * @date 2020/3/12 6 | **/ 7 | 8 | import org.apache.catalina.connector.Connector; 9 | import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | /** 14 | * @Author: Blue 15 | * 解决springboot项目请求出现非法字符问题 java.lang.IllegalArgumentException: 16 | * Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 17 | **/ 18 | @Configuration 19 | public class TomcatConfig { 20 | 21 | @Bean 22 | public TomcatServletWebServerFactory webServerFactory() { 23 | TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); 24 | factory.addConnectorCustomizers((Connector connector) -> { 25 | connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}"); 26 | connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}"); 27 | }); 28 | return factory; 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/FaceGetList.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import cn.blue.mall.consts.FaceConst; 4 | import cn.blue.mall.service.impl.AuthServiceImpl; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * 获取用户人脸列表 10 | * @author Blue 11 | * @date 2020/5/4 12 | */ 13 | public class FaceGetList { 14 | 15 | public static String faceGetList() { 16 | // 请求url 17 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/getusers"; 18 | try { 19 | Map map = new HashMap<>(); 20 | map.put("group_id", FaceConst.GROUP_ID); 21 | 22 | String param = GsonUtils.toJson(map); 23 | 24 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 25 | String accessToken = AuthServiceImpl.getAuth(); 26 | 27 | String result = HttpUtil.post(url, accessToken, "application/json", param); 28 | System.out.println(result); 29 | return result; 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | return null; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/impl/PowersServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service.impl; 2 | 3 | import cn.blue.mall.bean.Powers; 4 | import cn.blue.mall.mapper.PowersMapper; 5 | import cn.blue.mall.service.PowersService; 6 | import org.springframework.stereotype.Service; 7 | 8 | import javax.annotation.Resource; 9 | import java.util.List; 10 | 11 | /** 12 | * @author Blue 13 | * @date 2020/3/5 14 | **/ 15 | @Service("powersService") 16 | public class PowersServiceImpl implements PowersService { 17 | @Resource 18 | private PowersMapper powersMapper; 19 | 20 | @Override 21 | public List findAll(Powers powers) { 22 | return powersMapper.findAll(powers); 23 | } 24 | 25 | @Override 26 | public List findPowersTree() { 27 | return powersMapper.findPowersTree(); 28 | } 29 | 30 | @Override 31 | public Powers findThirdGrade(Integer powersId) { 32 | return powersMapper.findThirdGrade(powersId); 33 | } 34 | 35 | @Override 36 | public boolean setPidByRolesId(Integer rolesId) { 37 | return powersMapper.setPidByRolesId(rolesId) > 0; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/FaceMatch.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | 4 | 5 | /** 6 | * 人脸对比 7 | * @author Blue 8 | * @date 2020/5/4 9 | */ 10 | public class FaceMatch { 11 | 12 | /** 13 | * 重要提示代码中所需工具类 14 | * FileUtil,Base64Util,HttpUtil,GsonUtils请从 15 | * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72 16 | * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2 17 | * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3 18 | * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3 19 | * 下载 20 | */ 21 | public static String faceMatch() { 22 | // 请求url 23 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/match"; 24 | try { 25 | //注释 TODO 26 | //String param = GsonUtils.toJson(map); 27 | 28 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 29 | String accessToken = "[调用鉴权接口获取的token]"; 30 | //注释 TODO 31 | //String result = HttpUtil.post(url, accessToken, "application/json", param); 32 | // System.out.println(result); 33 | // return result; 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/mapper/PowersMapper.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.mapper; 2 | 3 | import cn.blue.mall.bean.Powers; 4 | import cn.blue.mall.bean.RolesPowers; 5 | import org.apache.ibatis.annotations.Mapper; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | import java.util.List; 9 | 10 | @Mapper 11 | public interface PowersMapper { 12 | /** 13 | * 查询权限所有列表信息 14 | * 15 | * @return Powers集合 16 | */ 17 | public List findAll(Powers powers); 18 | 19 | /** 20 | * 查询一级权限下的所有列表信息 21 | * 22 | * @return Powers集合 23 | */ 24 | public List findAllFirstPowers(@Param("roles") Integer id); 25 | 26 | /** 27 | * 仅仅查询一级权限下的所有列表信息 28 | * 29 | * @return Powers集合 30 | */ 31 | public List findFirstPowers(@Param("roles") Integer id); 32 | 33 | /** 34 | * 权限树 35 | * 36 | * @return 权限树 37 | */ 38 | List findPowersTree(); 39 | 40 | /** 41 | * 42 | * @param id 角色id 43 | * @return 中间表角色对应的ids 44 | */ 45 | List findTreeByRolesId(Integer rolesId); 46 | 47 | /** 48 | * 查找是不是三级权限 49 | * @param powersId 角色id 50 | * @return 权限信息 51 | */ 52 | Powers findThirdGrade(Integer powersId); 53 | 54 | /** 55 | * 根据角色的id设置一级权限的pid 56 | * @param id 角色的id 57 | */ 58 | int setPidByRolesId(Integer rolesId); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/FaceSearch.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import cn.blue.mall.consts.FaceConst; 4 | import cn.blue.mall.service.impl.AuthServiceImpl; 5 | 6 | import java.io.File; 7 | import java.util.*; 8 | 9 | /** 10 | * 人脸搜索 11 | * @author Blue 12 | */ 13 | public class FaceSearch { 14 | 15 | public static String faceSearch(String filePath) { 16 | // 请求url 17 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/search"; 18 | File file = new File(filePath); 19 | try { 20 | Map map = new HashMap<>(); 21 | map.put("image", Base64Util.encode(FileUtil.readFileByBytes(filePath))); 22 | map.put("liveness_control", "NONE"); 23 | map.put("group_id_list", FaceConst.GROUP_ID); 24 | map.put("image_type", "BASE64"); 25 | map.put("quality_control", "LOW"); 26 | 27 | String param = GsonUtils.toJson(map); 28 | 29 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 30 | String accessToken = AuthServiceImpl.getAuth(); 31 | 32 | String result = HttpUtil.post(url, accessToken, "application/json", param); 33 | System.out.println(result); 34 | return result; 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | return null; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/test/java/cn/blue/mall/utils/FaceDetectTest.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import cn.blue.mall.face.Face_list; 4 | import cn.blue.mall.face.Face_shape; 5 | import cn.blue.mall.face.Face_type; 6 | import cn.blue.mall.face.JsonRootBean; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.io.File; 10 | import java.util.List; 11 | 12 | import static org.junit.jupiter.api.Assertions.*; 13 | 14 | class FaceDetectTest { 15 | 16 | @Test 17 | void faceDetect() { 18 | String URL = "D://Temp//"; 19 | File file=new File(URL); 20 | if (file.isDirectory()){//判断file是否是文件目录 若是返回TRUE 21 | String name[]=file.list();//name存储file文件夹中的文件名 22 | for (int i=0; i findAll(UserInfo userInfo) { 23 | return userInfoMapper.findAll(userInfo); 24 | } 25 | 26 | @Override 27 | public boolean updateStatusById(UserInfo userInfo) { 28 | return userInfoMapper.updateStatusById(userInfo) > 0; 29 | } 30 | 31 | @Override 32 | public boolean addUser(UserInfo userInfo) { 33 | String id = UUID.randomUUID().toString().replaceAll("-", ""); 34 | userInfo.setId(id); 35 | return userInfoMapper.addUser(userInfo) > 0; 36 | } 37 | 38 | @Override 39 | public boolean updateUserById(UserInfo userInfo) { 40 | return userInfoMapper.updateUserById(userInfo) > 0; 41 | } 42 | 43 | @Override 44 | public boolean deleteById(String id) { 45 | return userInfoMapper.deleteById(id) > 0; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/FaceAdd.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import cn.blue.mall.consts.FaceConst; 4 | import cn.blue.mall.service.impl.AuthServiceImpl; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.UUID; 9 | 10 | /** 11 | * 人脸注册 12 | * @author Blue 13 | */ 14 | public class FaceAdd { 15 | 16 | public static String faceAdd(String filePath) { 17 | // 请求url 18 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"; 19 | try { 20 | Map map = new HashMap<>(); 21 | map.put("image", Base64Util.encode(FileUtil.readFileByBytes(filePath))); 22 | String userId = UUID.randomUUID().toString().replace("-", "").substring(16) + System.currentTimeMillis(); 23 | map.put("group_id", FaceConst.GROUP_ID); 24 | map.put("user_id", userId); 25 | map.put("user_info", "abc"); 26 | map.put("liveness_control", "NONE"); 27 | map.put("image_type", "BASE64"); 28 | map.put("quality_control", "LOW"); 29 | 30 | String param = GsonUtils.toJson(map); 31 | 32 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 33 | String accessToken = AuthServiceImpl.getAuth(); 34 | 35 | String result = HttpUtil.post(url, accessToken, "application/json", param); 36 | System.out.println(result); 37 | return result; 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/controller/PowersController.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.controller; 2 | 3 | import cn.blue.mall.bean.Powers; 4 | import cn.blue.mall.service.PowersService; 5 | import cn.blue.mall.utils.Result; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | /** 15 | * @author Blue 16 | * @date 2020/3/10 17 | **/ 18 | @Controller 19 | @RequestMapping("/powers") 20 | public class PowersController { 21 | @Resource 22 | private PowersService powersService; 23 | 24 | @GetMapping("/list") 25 | @ResponseBody 26 | public Result findAll( 27 | ) { 28 | try { 29 | List list = powersService.findAll(null); 30 | return Result.success().setCode(200).setMsg("查询成功").add("data", list); 31 | } catch (Exception e) { 32 | e.printStackTrace(); 33 | return Result.error(500).setMsg(e.getMessage()); 34 | } 35 | } 36 | 37 | @GetMapping("/tree") 38 | @ResponseBody 39 | public Result findPowersTree( 40 | ) { 41 | try { 42 | List list = powersService.findPowersTree(); 43 | return Result.success().setCode(200).setMsg("查询成功").add("data", list); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | return Result.error(500).setMsg(e.getMessage()); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/mapper/RolesMapper.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.mapper; 2 | 3 | import cn.blue.mall.bean.Roles; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface RolesMapper { 11 | /** 12 | * 查询角色所有列表信息 13 | * 14 | * @return roles 15 | */ 16 | public List findAll(Roles roles); 17 | 18 | /** 19 | * 根据角色id来查权限树 20 | * 21 | * @param rolesId 角色id 22 | * @return 权限树 23 | */ 24 | List findTreeByRolesId(@Param("rolesId") Integer rolesId); 25 | 26 | /** 27 | * 根据角色id删除权限 28 | * 29 | * @param rolesId 角色id 30 | */ 31 | void deleteTreeByRolesId(@Param("rolesId") Integer rolesId); 32 | 33 | /** 34 | * @param ids 权限的数组 35 | * @return 受影响的行数目 36 | */ 37 | // int addTreeByPowerIds(@Param("rolesId") Integer rolesId, @Param("powersIds") Integer... ids); 38 | 39 | /** 40 | * 添加用户和权限的中间表 41 | * @param rolesId 角色id 42 | * @param powersId 权限id 43 | */ 44 | void addTreeByPowerId(Integer rolesId, Integer powersId); 45 | 46 | /** 47 | * 根据角色id来查展开后的权限树 48 | * 49 | * @param roles 角色id 50 | * @return 权限树 51 | */ 52 | List findAllPowers(Roles roles); 53 | 54 | /** 55 | * 根据角色id查询用户分配的角色 56 | * @param roles 角色id 57 | * @return 角色信息 58 | */ 59 | Roles findSetRoleByRoleId(@Param("rolesId") Integer roles); 60 | 61 | List findRolesAndFirstPower(); 62 | 63 | /** 64 | * 新增角色 65 | * @param roles 角色信息 66 | * @return 受影响的行数目 67 | */ 68 | int addNewRole(Roles roles); 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/FaceDetect.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | 4 | import cn.blue.mall.service.impl.AuthServiceImpl; 5 | 6 | import java.io.File; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * 人脸检测与属性分析 12 | * @author Blue 13 | */ 14 | public class FaceDetect { 15 | 16 | /** 17 | * 重要提示代码中所需工具类 18 | * FileUtil,Base64Util,HttpUtil,GsonUtils请从 19 | * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72 20 | * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2 21 | * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3 22 | * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3 23 | * 下载 24 | */ 25 | public static String faceDetect(String filePath) { 26 | File file = new File(filePath); 27 | // 请求url 28 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"; 29 | try { 30 | Map map = new HashMap<>(); 31 | map.put("image", Base64Util.encode(FileUtil.readFileByBytes(filePath))); 32 | // 返回的参数信息之间不要有空格,pic必须要有face 33 | map.put("face_field", "age,beauty,expression,face_shape,gender,glasses,race,quality,eye_status,emotion,face_type,location"); 34 | map.put("image_type", "BASE64"); 35 | String param = GsonUtils.toJson(map); 36 | 37 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 38 | String accessToken = AuthServiceImpl.getAuth(); 39 | String result = HttpUtil.post(url, accessToken, "application/json", param); 40 | System.out.println(result); 41 | return result; 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | return null; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /人脸识别返回参数示例.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": 0, 3 | "error_msg": "SUCCESS", 4 | "log_id": 1545754520120, 5 | "timestamp": 1588584397, 6 | "cached": 0, 7 | "result": { 8 | "face_num": 1, 9 | "face_list": [ 10 | { 11 | "face_token": "3462da5a8cc2e823866be47d2642685b", 12 | "location": { 13 | "left": 737.34, 14 | "top": 312.92, 15 | "width": 296, 16 | "height": 285, 17 | "rotation": -5 18 | }, 19 | "face_probability": 1, 20 | "angle": { 21 | "yaw": 11.63, 22 | "pitch": 4.7, 23 | "roll": -7.24 24 | }, 25 | "age": 22, 26 | "beauty": 60.25, 27 | "expression": { 28 | "type": "none", 29 | "probability": 1 30 | }, 31 | "face_shape": { 32 | "type": "round", 33 | "probability": 0.27 34 | }, 35 | "gender": { 36 | "type": "female", 37 | "probability": 1 38 | }, 39 | "glasses": { 40 | "type": "none", 41 | "probability": 1 42 | }, 43 | "race": { 44 | "type": "yellow", 45 | "probability": 1 46 | }, 47 | "quality": { 48 | "occlusion": { 49 | "left_eye": 0.02, 50 | "right_eye": 0.02, 51 | "nose": 0, 52 | "mouth": 0.3, 53 | "left_cheek": 0.05, 54 | "right_cheek": 0.48, 55 | "chin_contour": 0.99 56 | }, 57 | "blur": 0, 58 | "illumination": 199, 59 | "completeness": 1 60 | }, 61 | "eye_status": { 62 | "left_eye": 0.9999998808, 63 | "right_eye": 1 64 | }, 65 | "emotion": { 66 | "type": "", 67 | "probability": 0 68 | }, 69 | "face_type": { 70 | "type": "human", 71 | "probability": 0.97 72 | } 73 | } 74 | ] 75 | } 76 | } -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/impl/RolesServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service.impl; 2 | 3 | import cn.blue.mall.bean.Roles; 4 | import cn.blue.mall.mapper.PowersMapper; 5 | import cn.blue.mall.mapper.RolesMapper; 6 | import cn.blue.mall.service.RolesService; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.annotation.Resource; 10 | import java.util.List; 11 | 12 | /** 13 | * @author Blue 14 | * @date 2020/3/5 15 | **/ 16 | @Service("rolesService") 17 | public class RolesServiceImpl implements RolesService { 18 | @Resource 19 | private RolesMapper rolesMapper; 20 | @Resource 21 | private PowersMapper powersMapper; 22 | 23 | @Override 24 | public List findAll(Roles roles) { 25 | return rolesMapper.findAll(roles); 26 | } 27 | 28 | @Override 29 | public List findAllPowers(Roles roles) { 30 | return rolesMapper.findAllPowers(roles); 31 | } 32 | 33 | @Override 34 | public List findTreeByRolesId(Integer rolesId) { 35 | return rolesMapper.findTreeByRolesId(rolesId); 36 | } 37 | 38 | @Override 39 | public boolean updateTreeByIds(Integer[] ids, Integer rolesId) { 40 | // 根据用户id删除中间表中已有的权限 41 | try { 42 | rolesMapper.deleteTreeByRolesId(rolesId); 43 | for (Integer id : ids 44 | ) { 45 | rolesMapper.addTreeByPowerId(rolesId, id); 46 | } 47 | return true; 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | return false; 52 | } 53 | 54 | @Override 55 | public List findExpandTree() { 56 | /* 1.先找到所有角色列表 57 | 2.再给每个角色都赋予一级权限 58 | 3.再根据角色rolesId找到角色有的二级三级权限 59 | 4.找到二级权限对应的值 grade = 1 60 | 5找到三级权限 grade = 2 61 | */ 62 | return rolesMapper.findRolesAndFirstPower(); 63 | } 64 | 65 | @Override 66 | public boolean addNewRole(Roles roles) { 67 | return rolesMapper.addNewRole(roles) > 0; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * 文件读取工具类 7 | * @author Blue 8 | */ 9 | public class FileUtil { 10 | 11 | /** 12 | * 读取文件内容,作为字符串返回 13 | */ 14 | public static String readFileAsString(String filePath) throws IOException { 15 | File file = new File(filePath); 16 | if (!file.exists()) { 17 | throw new FileNotFoundException(filePath); 18 | } 19 | 20 | if (file.length() > 1024 * 1024 * 1024) { 21 | throw new IOException("File is too large"); 22 | } 23 | 24 | StringBuilder sb = new StringBuilder((int) (file.length())); 25 | // 创建字节输入流 26 | FileInputStream fis = new FileInputStream(filePath); 27 | // 创建一个长度为10240的Buffer 28 | byte[] bbuf = new byte[10240]; 29 | // 用于保存实际读取的字节数 30 | int hasRead = 0; 31 | while ( (hasRead = fis.read(bbuf)) > 0 ) { 32 | sb.append(new String(bbuf, 0, hasRead)); 33 | } 34 | fis.close(); 35 | return sb.toString(); 36 | } 37 | 38 | /** 39 | * 根据文件路径读取byte[] 数组 40 | */ 41 | public static byte[] readFileByBytes(String filePath) throws IOException { 42 | File file = new File(filePath); 43 | if (!file.exists()) { 44 | throw new FileNotFoundException(filePath); 45 | } else { 46 | ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length()); 47 | BufferedInputStream in = null; 48 | 49 | try { 50 | in = new BufferedInputStream(new FileInputStream(file)); 51 | short bufSize = 1024; 52 | byte[] buffer = new byte[bufSize]; 53 | int len1; 54 | while (-1 != (len1 = in.read(buffer, 0, bufSize))) { 55 | bos.write(buffer, 0, len1); 56 | } 57 | 58 | byte[] var7 = bos.toByteArray(); 59 | return var7; 60 | } finally { 61 | try { 62 | if (in != null) { 63 | in.close(); 64 | } 65 | } catch (IOException var14) { 66 | var14.printStackTrace(); 67 | } 68 | 69 | bos.close(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/Base64Util.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | /** 4 | * Base64 工具类 5 | */ 6 | public class Base64Util { 7 | private static final char last2byte = (char) Integer.parseInt("00000011", 2); 8 | private static final char last4byte = (char) Integer.parseInt("00001111", 2); 9 | private static final char last6byte = (char) Integer.parseInt("00111111", 2); 10 | private static final char lead6byte = (char) Integer.parseInt("11111100", 2); 11 | private static final char lead4byte = (char) Integer.parseInt("11110000", 2); 12 | private static final char lead2byte = (char) Integer.parseInt("11000000", 2); 13 | private static final char[] encodeTable = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; 14 | 15 | public Base64Util() { 16 | } 17 | 18 | public static String encode(byte[] from) { 19 | StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3); 20 | int num = 0; 21 | char currentByte = 0; 22 | 23 | int i; 24 | for (i = 0; i < from.length; ++i) { 25 | for (num %= 8; num < 8; num += 6) { 26 | switch (num) { 27 | case 0: 28 | currentByte = (char) (from[i] & lead6byte); 29 | currentByte = (char) (currentByte >>> 2); 30 | case 1: 31 | case 3: 32 | case 5: 33 | default: 34 | break; 35 | case 2: 36 | currentByte = (char) (from[i] & last6byte); 37 | break; 38 | case 4: 39 | currentByte = (char) (from[i] & last4byte); 40 | currentByte = (char) (currentByte << 2); 41 | if (i + 1 < from.length) { 42 | currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6); 43 | } 44 | break; 45 | case 6: 46 | currentByte = (char) (from[i] & last2byte); 47 | currentByte = (char) (currentByte << 4); 48 | if (i + 1 < from.length) { 49 | currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4); 50 | } 51 | } 52 | 53 | to.append(encodeTable[currentByte]); 54 | } 55 | } 56 | 57 | if (to.length() % 4 != 0) { 58 | for (i = 4 - to.length() % 4; i > 0; --i) { 59 | to.append("="); 60 | } 61 | } 62 | 63 | return to.toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/utils/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.utils; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.DataOutputStream; 5 | import java.io.InputStreamReader; 6 | import java.net.HttpURLConnection; 7 | import java.net.URL; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * http 工具类 13 | * @author Blue 14 | */ 15 | public class HttpUtil { 16 | 17 | public static String post(String requestUrl, String accessToken, String params) 18 | throws Exception { 19 | String contentType = "application/x-www-form-urlencoded"; 20 | return HttpUtil.post(requestUrl, accessToken, contentType, params); 21 | } 22 | 23 | public static String post(String requestUrl, String accessToken, String contentType, String params) 24 | throws Exception { 25 | String encoding = "UTF-8"; 26 | if (requestUrl.contains("nlp")) { 27 | encoding = "GBK"; 28 | } 29 | return HttpUtil.post(requestUrl, accessToken, contentType, params, encoding); 30 | } 31 | 32 | public static String post(String requestUrl, String accessToken, String contentType, String params, String encoding) 33 | throws Exception { 34 | String url = requestUrl + "?access_token=" + accessToken; 35 | return HttpUtil.postGeneralUrl(url, contentType, params, encoding); 36 | } 37 | 38 | public static String postGeneralUrl(String generalUrl, String contentType, String params, String encoding) 39 | throws Exception { 40 | URL url = new URL(generalUrl); 41 | // 打开和URL之间的连接 42 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 43 | connection.setRequestMethod("POST"); 44 | // 设置通用的请求属性 45 | connection.setRequestProperty("Content-Type", contentType); 46 | connection.setRequestProperty("Connection", "Keep-Alive"); 47 | connection.setUseCaches(false); 48 | connection.setDoOutput(true); 49 | connection.setDoInput(true); 50 | 51 | // 得到请求的输出流对象 52 | DataOutputStream out = new DataOutputStream(connection.getOutputStream()); 53 | out.write(params.getBytes(encoding)); 54 | out.flush(); 55 | out.close(); 56 | 57 | // 建立实际的连接 58 | connection.connect(); 59 | // 获取所有响应头字段 60 | Map> headers = connection.getHeaderFields(); 61 | // 遍历所有的响应头字段 62 | for (String key : headers.keySet()) { 63 | System.err.println(key + "--->" + headers.get(key)); 64 | } 65 | // 定义 BufferedReader输入流来读取URL的响应 66 | BufferedReader in = null; 67 | in = new BufferedReader( 68 | new InputStreamReader(connection.getInputStream(), encoding)); 69 | String result = ""; 70 | String getLine; 71 | while ((getLine = in.readLine()) != null) { 72 | result += getLine; 73 | } 74 | in.close(); 75 | System.err.println("result:" + result); 76 | return result; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/controller/GoodsController.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.controller; 2 | 3 | import cn.blue.mall.bean.GoodsInfo; 4 | import cn.blue.mall.service.GoodsService; 5 | import cn.blue.mall.utils.Result; 6 | import com.github.pagehelper.PageHelper; 7 | import com.github.pagehelper.PageInfo; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * @author Blue 17 | * @date 2020/3/15 18 | **/ 19 | @Controller 20 | @RequestMapping("/goods") 21 | public class GoodsController { 22 | @Resource 23 | private GoodsService goodsService; 24 | 25 | @GetMapping 26 | @ResponseBody 27 | public Result findAll( 28 | @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum, 29 | @RequestParam(name = "pageSize", required = false, defaultValue = "5") Integer pageSize, 30 | GoodsInfo goodsInfo) { 31 | PageHelper.startPage(pageNum, pageSize); 32 | // 这里默认将 catLevel=0传过来 33 | List list = goodsService.findAll(goodsInfo); 34 | PageInfo pageInfo = new PageInfo<>(list); 35 | Result r = Result.success(); 36 | r.add("total", pageInfo.getTotal()); 37 | r.add("data", list); 38 | r.setMsg("查询成功"); 39 | return r; 40 | } 41 | 42 | /** 43 | * 只保留一级、二级分类 44 | * @param goodsInfo 传catLevel=0 45 | * @return 一级二级分类列表 46 | */ 47 | @GetMapping("/filterCat") 48 | @ResponseBody 49 | public Result findAll(GoodsInfo goodsInfo) { 50 | try { 51 | // 这里默认将 catLevel=0传过来 52 | List list = goodsService.findAll(goodsInfo); 53 | // 复制集合,将只保留一级、二级分类 54 | ArrayList arrayList = new ArrayList<>(list); 55 | arrayList.forEach(item -> { 56 | item.getChildren().forEach(goods -> { 57 | goods.setChildren(null); 58 | }); 59 | }); 60 | return Result.success().setCode(200).setMsg("查询成功").add("goods",arrayList); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | return Result.error(500).setMsg(e.getMessage()); 64 | } 65 | } 66 | 67 | @ResponseBody 68 | @PutMapping("/update") 69 | public Result updateById(GoodsInfo goodsInfo) { 70 | try { 71 | goodsService.updateById(goodsInfo); 72 | return Result.success().setCode(200).setMsg("修改成功"); 73 | } catch (Exception e) { 74 | e.printStackTrace(); 75 | return Result.error(500).setMsg(e.getMessage()); 76 | } 77 | } 78 | 79 | 80 | @ResponseBody 81 | @PostMapping("/addCat") 82 | public Result addCat(GoodsInfo goodsInfo) { 83 | try { 84 | goodsService.addCatByPId(goodsInfo); 85 | return Result.success().setCode(200).setMsg("添加成功"); 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | return Result.error(500).setMsg(e.getMessage()); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/service/impl/AuthServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.service.impl; 2 | 3 | /** 4 | * @author Blue 5 | * @date 2020/5/4 6 | **/ 7 | 8 | 9 | import cn.blue.mall.consts.FaceConst; 10 | import org.json.JSONObject; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.InputStreamReader; 14 | import java.net.HttpURLConnection; 15 | import java.net.URL; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * 获取token类 21 | * @author Blue 22 | */ 23 | public class AuthServiceImpl { 24 | 25 | /** 26 | * 获取权限token 27 | * @return 返回示例: 28 | * { 29 | * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567", 30 | * "expires_in": 2592000 31 | * } 32 | */ 33 | public static String getAuth() { 34 | // 官网获取的 API Key 更新为你注册的 35 | String clientId = FaceConst.CLIENT_ID; 36 | // 官网获取的 Secret Key 更新为你注册的 37 | String clientSecret = FaceConst.CLIENT_SECRET; 38 | return getAuth(clientId, clientSecret); 39 | } 40 | 41 | /** 42 | * 获取API访问token 43 | * 该token有一定的有效期,需要自行管理,当失效时需重新获取. 44 | * @param ak - 百度云官网获取的 API Key 45 | * @param sk - 百度云官网获取的 Securet Key 46 | * @return assess_token 示例: 47 | * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567" 48 | */ 49 | public static String getAuth(String ak, String sk) { 50 | // 获取token地址 51 | String authHost = "https://aip.baidubce.com/oauth/2.0/token?"; 52 | String getAccessTokenUrl = authHost 53 | // 1. grant_type为固定参数 54 | + "grant_type=client_credentials" 55 | // 2. 官网获取的 API Key 56 | + "&client_id=" + ak 57 | // 3. 官网获取的 Secret Key 58 | + "&client_secret=" + sk; 59 | try { 60 | URL realUrl = new URL(getAccessTokenUrl); 61 | // 打开和URL之间的连接 62 | HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); 63 | connection.setRequestMethod("GET"); 64 | connection.connect(); 65 | // 获取所有响应头字段 66 | Map> map = connection.getHeaderFields(); 67 | // 遍历所有的响应头字段 68 | for (String key : map.keySet()) { 69 | System.err.println(key + "--->" + map.get(key)); 70 | } 71 | // 定义 BufferedReader输入流来读取URL的响应 72 | BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 73 | String result = ""; 74 | String line; 75 | while ((line = in.readLine()) != null) { 76 | result += line; 77 | } 78 | /** 79 | * 返回结果示例 80 | */ 81 | System.err.println("result:" + result); 82 | JSONObject jsonObject = new JSONObject(result); 83 | String access_token = jsonObject.getString("access_token"); 84 | return access_token; 85 | } catch (Exception e) { 86 | System.err.printf("获取token失败!"); 87 | e.printStackTrace(System.err); 88 | } 89 | return null; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/resources/mapper/GoodsMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | ID, CAT_NAME, CAT_PID, CAT_DELETED, CAT_LEVEL 25 | 26 | 27 | 28 | 29 | 30 | AND ID=#{id} 31 | 32 | 33 | AND CAT_NAME=#{catName} 34 | 35 | 36 | AND CAT_PID=#{catPid} 37 | 38 | 39 | AND CAT_LEVEL=#{catLevel} 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | ID=#{id}, 48 | 49 | 50 | CAT_NAME=#{catName}, 51 | 52 | 53 | CAT_DELETED=#{catDeleted}, 54 | 55 | 56 | 57 | 58 | insert into mall_goods(cat_name,cat_pid,cat_level,cat_deleted) 59 | values( #{catName},#{catPid} ,#{catLevel}, #{catDeleted}) 60 | 61 | 62 | 63 | update MALL_GOODS 64 | 65 | where ID = #{id} 66 | 67 | 68 | 69 | 73 | 74 | 75 | 80 | 81 | 82 | 87 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/controller/UserInfoController.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.controller; 2 | 3 | import cn.blue.mall.bean.UserInfo; 4 | import cn.blue.mall.service.UserInfoService; 5 | import cn.blue.mall.utils.Result; 6 | import com.github.pagehelper.PageHelper; 7 | import com.github.pagehelper.PageInfo; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | /** 15 | * @author Blue 16 | * @date 2020/3/5 17 | **/ 18 | @Controller 19 | @RequestMapping("/users") 20 | public class UserInfoController { 21 | @Resource 22 | private UserInfoService userInfoService; 23 | 24 | @PutMapping("/changeStatus") 25 | @ResponseBody 26 | public Result changeStatus(UserInfo userInfo) { 27 | try { 28 | if (userInfoService.updateStatusById(userInfo)) { 29 | return Result.success().setCode(200).setMsg("修改成功"); 30 | } 31 | } catch (Exception e) { 32 | e.printStackTrace(); 33 | } 34 | return Result.error(500).setMsg("修改失败"); 35 | } 36 | 37 | @PostMapping("/add") 38 | @ResponseBody 39 | public Result addUser(UserInfo userInfo) { 40 | if (userInfo != null) { 41 | try { 42 | if (userInfo.getId() != null && !userInfo.getId().equals("")) { 43 | userInfoService.updateUserById(userInfo); 44 | return Result.success().setCode(200).setMsg("修改成功"); 45 | } else { 46 | userInfoService.addUser(userInfo); 47 | return Result.success().setCode(200).setMsg("添加成功"); 48 | } 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | return Result.error(500).setMsg("添加失败"); 54 | } 55 | 56 | @ResponseBody 57 | @DeleteMapping("/delete") 58 | public Result deleteById(@RequestParam("userId") String id) { 59 | try { 60 | userInfoService.deleteById(id); 61 | return Result.success().setCode(200).setMsg("删除成功"); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | return Result.error(500).setMsg(e.getMessage()); 65 | } 66 | } 67 | 68 | @GetMapping 69 | @ResponseBody 70 | public Result findAll( 71 | @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum, 72 | @RequestParam(name = "pageSize", required = false, defaultValue = "3") Integer pageSize, 73 | UserInfo user) { 74 | PageHelper.startPage(pageNum, pageSize); 75 | List list = null; 76 | if (user == null) { 77 | list = userInfoService.findAll(null); 78 | } else { 79 | list = userInfoService.findAll(user); 80 | } 81 | PageInfo pageInfo = new PageInfo<>(list); 82 | Result r = Result.success(); 83 | r.add("total", pageInfo.getTotal()); 84 | r.add("data", list); 85 | r.setMsg("查询成功"); 86 | return r; 87 | } 88 | 89 | @PutMapping("/setRoles") 90 | @ResponseBody 91 | public Result updateRolesById(UserInfo userInfo) { 92 | try { 93 | userInfoService.updateUserById(userInfo); 94 | return Result.success().setCode(200).setMsg("修改成功"); 95 | } catch (Exception e) { 96 | e.printStackTrace(); 97 | return Result.error(500).setMsg("修改失败"); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/resources/mapper/RolesMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | ID,ROLE_NAME,ROLE_DESC 29 | 30 | 31 | 32 | 33 | 34 | ID=#{id} 35 | 36 | 37 | ROLENAME=#{role_name} 38 | 39 | 40 | ROLEDESC=#{role_desc} 41 | 42 | 43 | 44 | 45 | 46 | INSERT INTO 47 | roles_powers(roles_id, powers_id) 48 | VALUES 49 | (#{rolesId},#{powersId}) 50 | 51 | 52 | 53 | DELETE 54 | FROM roles_powers 55 | WHERE 56 | roles_id = #{rolesId} 57 | 58 | 59 | 66 | 67 | 73 | 74 | 81 | 82 | 86 | 87 | 92 | 93 | 94 | insert into MALL_ROLES(ROLE_NAME, ROLE_DESC) 95 | values (#{roleName}, #{roleDesc}) 96 | 97 | -------------------------------------------------------------------------------- /src/main/resources/mapper/UserInfoMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | ID ,NAME, PASSWORD, EMAIL, TELEPHONE, ROLE, STATUS 17 | 18 | 19 | 20 | 21 | 22 | AND ID=#{id} 23 | 24 | 25 | 26 | 27 | AND NAME like concat(concat('%',#{name}),'%') 28 | 29 | 30 | 31 | 32 | AND EMAIL=#{email} 33 | 34 | 35 | 36 | 37 | AND TELEPHONE=#{telephone} 38 | 39 | 40 | 41 | 42 | AND ROLE=#{role} 43 | 44 | 45 | 46 | 47 | AND STATUS=#{status} 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | NAME=#{name}, 56 | 57 | 58 | TELEPHONE=#{telephone}, 59 | 60 | 61 | EMAIL=#{email}, 62 | 63 | 64 | PASSWORD=#{password}, 65 | 66 | 67 | ROLE=#{role}, 68 | 69 | 70 | STATUS=#{status}, 71 | 72 | 73 | 74 | 75 | 82 | 83 | 84 | UPDATE MALL_USERS 85 | SET status = #{userInfo.status} 86 | WHERE id=#{userInfo.id} 87 | 88 | 89 | 91 | INSERT INTO MALL_USERS(ID, NAME, PASSWORD, EMAIL, TELEPHONE) 92 | VALUES (#{id}, #{name}, #{password}, #{email}, #{telephone}) 93 | 94 | 95 | 96 | update MALL_USERS 97 | 98 | WHERE ID = #{id} 99 | 100 | 101 | 102 | DELETE FROM MALL_USERS 103 | WHERE ID = #{id} 104 | 105 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/controller/RolesController.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.controller; 2 | 3 | import cn.blue.mall.bean.Roles; 4 | import cn.blue.mall.service.PowersService; 5 | import cn.blue.mall.service.RolesService; 6 | import cn.blue.mall.utils.Result; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import javax.annotation.Resource; 11 | import java.util.List; 12 | 13 | /** 14 | * @author Blue 15 | * @date 2020/3/10 16 | **/ 17 | @Controller 18 | @RequestMapping("/roles") 19 | public class RolesController { 20 | @Resource 21 | private RolesService rolesService; 22 | @Resource 23 | private PowersService powersService; 24 | 25 | @GetMapping("/list") 26 | @ResponseBody 27 | public Result findAll() { 28 | try { 29 | List list = rolesService.findAll(null); 30 | return Result.success().setCode(200).setMsg("查询成功").add("data", list); 31 | } catch (Exception e) { 32 | e.printStackTrace(); 33 | return Result.error(500).setMsg(e.getMessage()); 34 | } 35 | } 36 | 37 | /** 38 | * 查找角色列表展开后的权限 39 | */ 40 | @PutMapping("/expandTree") 41 | @ResponseBody 42 | public Result findExpandTree(Roles roles) { 43 | try { 44 | // 修改一级权限的pid 45 | List list = null; 46 | // if (powersService.setPidByRolesId(roles.getId())) { 47 | list = rolesService.findExpandTree(); 48 | // } 49 | return Result.success().setCode(200).setMsg("查询成功").add("data", list); 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | return Result.error(500).setMsg(e.getMessage()); 53 | } 54 | } 55 | 56 | /** 57 | * @return 查找列表展开后的权限 58 | */ 59 | @GetMapping("/findAll") 60 | @ResponseBody 61 | public Result findAllPowers() { 62 | try { 63 | List list = rolesService.findAllPowers(null); 64 | return Result.success().setCode(200).setMsg("查询成功").add("data", list); 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | return Result.error(500).setMsg(e.getMessage()); 68 | } 69 | } 70 | 71 | @GetMapping(path = {"/{rolesId}"}) 72 | @ResponseBody 73 | public Result findTreeByRolesId(@PathVariable("rolesId") Integer rolesId) { 74 | try { 75 | List tree = rolesService.findTreeByRolesId(rolesId); 76 | tree.forEach(item -> item.getPowers().forEach(power -> { 77 | // 如果是三级权限就设置true,前端只需要它被勾选。 78 | if (powersService.findThirdGrade(power.getId()) != null) { 79 | power.setHaveChildren(true); 80 | } 81 | } 82 | )); 83 | return Result.success().setCode(200).setMsg("查询成功").add("data", tree); 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | return Result.error(500).setMsg(e.getMessage()); 87 | } 88 | } 89 | 90 | @PostMapping(path = {"/updateTree/{rolesId}"}) 91 | @ResponseBody 92 | public Result updateTreeByIds(Integer[] ids, @PathVariable(name = "rolesId") Integer rolesId) { 93 | // 有个小问题:直接在mybatis中用foreach标签新增数据,提示sql命令不正确,以前同样如此,为什么就可以了。 94 | try { 95 | if (rolesService.updateTreeByIds(ids, rolesId)) { 96 | return Result.success().setCode(200).setMsg("修改成功"); 97 | } 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | return Result.error(500).setMsg(e.getMessage()); 101 | } 102 | return Result.error(500).setMsg("更新失败"); 103 | } 104 | 105 | @ResponseBody 106 | @PostMapping("/add") 107 | public Result addRole(Roles roles) { 108 | try { 109 | if(rolesService.addNewRole(roles)) { 110 | return Result.success().setCode(200).setMsg("新增成功"); 111 | } 112 | } catch (Exception e) { 113 | e.printStackTrace(); 114 | } 115 | return Result.error(500).setMsg("新增失败"); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.5.RELEASE 9 | 10 | 11 | cn.blue 12 | mall 13 | 0.0.1-SNAPSHOT 14 | mall 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-devtools 29 | runtime 30 | true 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | true 36 | 37 | 38 | org.mybatis.spring.boot 39 | mybatis-spring-boot-starter 40 | 2.1.1 41 | 42 | 43 | com.alibaba 44 | druid 45 | 1.1.20 46 | 47 | 48 | com.github.pagehelper 49 | pagehelper-spring-boot-starter 50 | 1.2.12 51 | 52 | 53 | org.apache.logging.log4j.adapters 54 | log4j-to-slf4j 55 | 2.0-beta4 56 | 57 | 58 | mysql 59 | mysql-connector-java 60 | runtime 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | test 66 | 67 | 68 | org.junit.vintage 69 | junit-vintage-engine 70 | 71 | 72 | 73 | 74 | 75 | com.google.code.gson 76 | gson 77 | 2.8.5 78 | 79 | 80 | 81 | com.vaadin.external.google 82 | android-json 83 | 0.0.20131108.vaadin1 84 | compile 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.springframework.boot 100 | spring-boot-maven-plugin 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/main/java/cn/blue/mall/controller/FaceController.java: -------------------------------------------------------------------------------- 1 | package cn.blue.mall.controller; 2 | 3 | import cn.blue.mall.bean.FaceInfo; 4 | import cn.blue.mall.consts.FaceConst; 5 | import cn.blue.mall.face.Face_type; 6 | import cn.blue.mall.face.JsonRootBean; 7 | import cn.blue.mall.utils.*; 8 | import lombok.SneakyThrows; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.ResponseBody; 13 | import sun.misc.BASE64Decoder; 14 | 15 | import java.io.File; 16 | import java.io.FileOutputStream; 17 | import java.io.IOException; 18 | import java.io.OutputStream; 19 | 20 | /** 21 | * @author Blue 22 | * @date 2020/5/4 23 | * 人脸识别接口调用 24 | **/ 25 | @Controller 26 | @RequestMapping("/login") 27 | public class FaceController { 28 | /** 29 | * 登录访问次数 30 | */ 31 | static Integer COUNT = 0; 32 | 33 | @SneakyThrows 34 | @ResponseBody 35 | @PostMapping("/face") 36 | public Result loginByFace(String imgSrc) { 37 | //对字节数组字符串进行Base64解码并生成图片 38 | if (imgSrc == null) { 39 | return Result.error(500).setMsg("参数异常"); 40 | } 41 | BASE64Decoder decoder = new BASE64Decoder(); 42 | String imgFilePath = FaceConst.PATH_PRE + System.currentTimeMillis() + FaceConst.PATH_SUF; 43 | try (OutputStream out = new FileOutputStream(imgFilePath)) { 44 | //Base64解码 45 | //生成jpeg图片 46 | byte[] decoderBytes = decoder.decodeBuffer(imgSrc.split(",")[1]); 47 | out.write(decoderBytes); 48 | // 搜索人脸库 49 | String resultJson = FaceSearch.faceSearch(imgFilePath); 50 | FaceInfo faceInfo = GsonUtils.fromJson(resultJson, FaceInfo.class); 51 | 52 | COUNT ++; 53 | if(COUNT % 10 == 0) { 54 | File file = new File(FaceConst.PATH_PRE); 55 | // 判断file是否是文件目录 若是返回TRUE 56 | if (file.isDirectory()) { 57 | // name存储file文件夹中的文件名 58 | String name[] = file.list(); 59 | for (int i = 0; i < name.length; i++) { 60 | // 此时就可得到文件夹中的文件 61 | File f = new File(FaceConst.PATH_PRE, name[i]); 62 | // 删除文件 63 | f.delete(); 64 | } 65 | } 66 | } 67 | 68 | if (!faceInfo.getError_msg().equals(FaceConst.ERROR_MSG)) { 69 | return Result.error(500).setMsg("请正确拍摄到人像"); 70 | } 71 | if (faceInfo.getResult().getUser_list().get(0).getScore() >= FaceConst.SCORE) { 72 | return Result.success().setMsg("人脸识别成功"); 73 | } else { 74 | return Result.error(500).setMsg("人脸库未匹配成功,请先注册!"); 75 | } 76 | } 77 | } 78 | 79 | @ResponseBody 80 | @PostMapping("/register") 81 | public Result registerByFace(String imgSrc) { 82 | if (imgSrc == null) { 83 | return Result.error(500).setMsg("参数异常"); 84 | } 85 | BASE64Decoder decoder = new BASE64Decoder(); 86 | String imgFilePath = "D:\\Temp\\" + System.currentTimeMillis() + "_face.jpg"; 87 | try (OutputStream out = new FileOutputStream(imgFilePath)) { 88 | //Base64解码 89 | //生成jpeg图片 90 | byte[] decoderBytes = decoder.decodeBuffer(imgSrc.split(",")[1]); 91 | out.write(decoderBytes); 92 | String resultJson = FaceDetect.faceDetect(imgFilePath); 93 | JsonRootBean jsonRootBean = GsonUtils.fromJson(resultJson, JsonRootBean.class); 94 | if (!jsonRootBean.getError_msg().equals(FaceConst.ERROR_MSG)) { 95 | return Result.error(500).setMsg("请正确拍摄到人像"); 96 | } 97 | Face_type faceType = jsonRootBean.getResult().getFace_list().get(0).getFace_type(); 98 | if (!("human".equals(faceType.getType()) && 99 | faceType.getProbability() >= 0.80)) { 100 | return Result.error(500).setMsg("人脸完整度不够"); 101 | } 102 | String resultJson1 = FaceAdd.faceAdd(imgFilePath); 103 | if (resultJson1 != null) { 104 | return Result.success().setMsg("人脸注册成功"); 105 | } 106 | } catch (IOException e) { 107 | e.printStackTrace(); 108 | } 109 | return Result.error(500).setMsg("人脸注册失败"); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/resources/mapper/PowersMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | ID,AUTH_NAME,GRADE,PID,PATH 41 | 42 | 43 | 44 | 45 | 46 | AND ID=#{id} 47 | 48 | 49 | AND authName=#{auth_name} 50 | 51 | 52 | AND GRADE=#{grade} 53 | 54 | 55 | AND PID=#{pid} 56 | 57 | 58 | 59 | 60 | 61 | update MALL_POWERS 62 | set PID = #{rolesId} 63 | where grade = 0 64 | 65 | 66 | 73 | 74 | 80 | 81 | 88 | 89 | 90 | 97 | 98 | 99 | 105 | 106 | 107 | 112 | 113 | 114 | 120 | 121 | 126 | 127 | 134 | 135 | 141 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /mall_vue.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : TYKY 5 | Source Server Type : MySQL 6 | Source Server Version : 80012 7 | Source Host : localhost:3306 8 | Source Schema : mall_vue 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 80012 12 | File Encoding : 65001 13 | 14 | Date: 16/03/2020 17:11:33 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for mall_goods 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `mall_goods`; 24 | CREATE TABLE `mall_goods` ( 25 | `id` int(11) NOT NULL, 26 | `cat_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 27 | `cat_deleted` int(255) NOT NULL, 28 | `cat_level` int(255) NOT NULL, 29 | `cat_pid` int(11) NOT NULL, 30 | PRIMARY KEY (`id`) USING BTREE 31 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 32 | 33 | -- ---------------------------- 34 | -- Records of mall_goods 35 | -- ---------------------------- 36 | INSERT INTO `mall_goods` VALUES (100, '大家电', 0, 0, 0); 37 | INSERT INTO `mall_goods` VALUES (101, '电视', 0, 1, 100); 38 | INSERT INTO `mall_goods` VALUES (102, '空调', 0, 1, 100); 39 | INSERT INTO `mall_goods` VALUES (103, '海信', 0, 2, 101); 40 | INSERT INTO `mall_goods` VALUES (104, '威视', 0, 2, 101); 41 | INSERT INTO `mall_goods` VALUES (105, '美菱', 0, 2, 102); 42 | INSERT INTO `mall_goods` VALUES (106, '热门推荐', 0, 0, 0); 43 | INSERT INTO `mall_goods` VALUES (107, '圣诞狂欢', 0, 1, 106); 44 | INSERT INTO `mall_goods` VALUES (108, '面膜', 0, 2, 107); 45 | INSERT INTO `mall_goods` VALUES (110, '海外购', 0, 0, 0); 46 | INSERT INTO `mall_goods` VALUES (111, '康佳', 0, 2, 101); 47 | INSERT INTO `mall_goods` VALUES (112, '圣诞套装', 0, 2, 107); 48 | INSERT INTO `mall_goods` VALUES (113, '格力', 0, 2, 102); 49 | INSERT INTO `mall_goods` VALUES (114, '长虹', 0, 2, 101); 50 | INSERT INTO `mall_goods` VALUES (115, '麋鹿', 0, 2, 107); 51 | INSERT INTO `mall_goods` VALUES (116, '圣诞玩具', 0, 2, 107); 52 | INSERT INTO `mall_goods` VALUES (117, '海外购', 0, 2, 101); 53 | 54 | -- ---------------------------- 55 | -- Table structure for mall_powers 56 | -- ---------------------------- 57 | DROP TABLE IF EXISTS `mall_powers`; 58 | CREATE TABLE `mall_powers` ( 59 | `id` int(11) NOT NULL, 60 | `auth_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 61 | `grade` int(255) NOT NULL, 62 | `pid` int(11) NULL DEFAULT NULL, 63 | `path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 64 | PRIMARY KEY (`id`) USING BTREE 65 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 66 | 67 | -- ---------------------------- 68 | -- Records of mall_powers 69 | -- ---------------------------- 70 | INSERT INTO `mall_powers` VALUES (101, '商品管理', 0, 1001, 'goods'); 71 | INSERT INTO `mall_powers` VALUES (102, '用户管理', 0, 1001, 'users'); 72 | INSERT INTO `mall_powers` VALUES (103, '订单管理', 0, 1001, 'orders'); 73 | INSERT INTO `mall_powers` VALUES (104, '权限管理', 0, 1001, 'rights'); 74 | INSERT INTO `mall_powers` VALUES (105, '数据统计', 0, 1001, 'reports'); 75 | INSERT INTO `mall_powers` VALUES (201, '商品列表', 1, 101, 'goods'); 76 | INSERT INTO `mall_powers` VALUES (202, '添加商品', 2, 201, 'goods'); 77 | INSERT INTO `mall_powers` VALUES (203, '商品修改', 2, 201, 'goods'); 78 | INSERT INTO `mall_powers` VALUES (204, '商品删除', 2, 201, 'goods'); 79 | INSERT INTO `mall_powers` VALUES (205, '更新商品图片', 2, 201, 'goods'); 80 | INSERT INTO `mall_powers` VALUES (206, '更新商品属性', 2, 201, 'goods'); 81 | INSERT INTO `mall_powers` VALUES (207, '更新商品状态', 2, 201, 'goods'); 82 | INSERT INTO `mall_powers` VALUES (208, '更新商品详情', 2, 201, 'goods'); 83 | INSERT INTO `mall_powers` VALUES (302, '分类参数', 1, 101, 'params'); 84 | INSERT INTO `mall_powers` VALUES (303, '获取参数列表', 2, 302, 'categories'); 85 | INSERT INTO `mall_powers` VALUES (304, '创建商品参数', 2, 302, 'categories'); 86 | INSERT INTO `mall_powers` VALUES (305, '删除商品参数', 2, 302, 'categories'); 87 | INSERT INTO `mall_powers` VALUES (403, '商品分类', 1, 101, 'categories'); 88 | INSERT INTO `mall_powers` VALUES (405, '添加分类', 2, 403, 'categories'); 89 | INSERT INTO `mall_powers` VALUES (406, '删除分类', 2, 403, 'categories'); 90 | INSERT INTO `mall_powers` VALUES (407, '获取分类详情', 2, 403, 'categories'); 91 | INSERT INTO `mall_powers` VALUES (504, '订单列表', 1, 103, 'orders'); 92 | INSERT INTO `mall_powers` VALUES (505, '添加订单', 2, 504, 'orders'); 93 | INSERT INTO `mall_powers` VALUES (506, '订单更新', 2, 504, 'orders'); 94 | INSERT INTO `mall_powers` VALUES (507, '获取订单详情', 2, 504, 'orders'); 95 | INSERT INTO `mall_powers` VALUES (605, '角色列表', 1, 104, 'roles'); 96 | INSERT INTO `mall_powers` VALUES (606, '添加角色', 2, 605, 'roles'); 97 | INSERT INTO `mall_powers` VALUES (607, '删除角色', 2, 605, 'roles'); 98 | INSERT INTO `mall_powers` VALUES (608, '角色授权', 2, 605, 'roles'); 99 | INSERT INTO `mall_powers` VALUES (609, '取消角色授权', 2, 605, 'roles'); 100 | INSERT INTO `mall_powers` VALUES (610, '获取角色列表', 2, 605, 'roles'); 101 | INSERT INTO `mall_powers` VALUES (611, '获取角色详情', 2, 605, 'roles'); 102 | INSERT INTO `mall_powers` VALUES (612, '更新角色信息', 2, 605, 'roles'); 103 | INSERT INTO `mall_powers` VALUES (613, '更新角色权限', 2, 605, 'roles'); 104 | INSERT INTO `mall_powers` VALUES (706, '权限列表', 1, 104, 'rights'); 105 | INSERT INTO `mall_powers` VALUES (708, '查看权限', 2, 706, 'rights'); 106 | INSERT INTO `mall_powers` VALUES (802, '设置管理状态', 2, 807, 'users'); 107 | INSERT INTO `mall_powers` VALUES (803, '分配用户角色', 2, 807, 'users'); 108 | INSERT INTO `mall_powers` VALUES (804, '获取用户详情', 2, 807, 'users'); 109 | INSERT INTO `mall_powers` VALUES (805, '更新用户', 2, 807, 'users'); 110 | INSERT INTO `mall_powers` VALUES (806, '删除用户', 2, 807, 'users'); 111 | INSERT INTO `mall_powers` VALUES (807, '用户列表', 1, 102, 'users'); 112 | INSERT INTO `mall_powers` VALUES (808, '添加用户', 2, 807, 'users'); 113 | INSERT INTO `mall_powers` VALUES (908, '数据报表', 1, 105, 'reports'); 114 | INSERT INTO `mall_powers` VALUES (909, '查看数据', 2, 908, 'reports'); 115 | 116 | -- ---------------------------- 117 | -- Table structure for mall_roles 118 | -- ---------------------------- 119 | DROP TABLE IF EXISTS `mall_roles`; 120 | CREATE TABLE `mall_roles` ( 121 | `id` int(11) NULL DEFAULT NULL, 122 | `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 123 | `role_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL 124 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 125 | 126 | -- ---------------------------- 127 | -- Records of mall_roles 128 | -- ---------------------------- 129 | INSERT INTO `mall_roles` VALUES (2, 'hhh', 'hhhh'); 130 | INSERT INTO `mall_roles` VALUES (3, '测试', '测试'); 131 | INSERT INTO `mall_roles` VALUES (1, '市场总监', '主管市场'); 132 | INSERT INTO `mall_roles` VALUES (1000, '主管', '技术负责人'); 133 | INSERT INTO `mall_roles` VALUES (1001, '经理', '行政管理'); 134 | INSERT INTO `mall_roles` VALUES (1002, '销售员', '产品销售'); 135 | 136 | -- ---------------------------- 137 | -- Table structure for mall_users 138 | -- ---------------------------- 139 | DROP TABLE IF EXISTS `mall_users`; 140 | CREATE TABLE `mall_users` ( 141 | `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 142 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 143 | `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 144 | `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 145 | `telephone` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 146 | `role` int(255) NULL DEFAULT NULL, 147 | `status` int(255) NULL DEFAULT 0, 148 | PRIMARY KEY (`id`) USING BTREE 149 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 150 | 151 | -- ---------------------------- 152 | -- Records of mall_users 153 | -- ---------------------------- 154 | INSERT INTO `mall_users` VALUES ('5dc1e96a057944c98c99f28d56334736', '13878447', '13878447846', '13878447846@qq.com', '13878447846', 1, 0); 155 | INSERT INTO `mall_users` VALUES ('abc-123', 'Jobe', '123456212', '535523024@qq.com', '13678259451', 1000, 1); 156 | INSERT INTO `mall_users` VALUES ('abc-124', 'Jim', '123456', '535523024@qq.com', '17672259451', 1002, 1); 157 | INSERT INTO `mall_users` VALUES ('abc-125', 'Jenny', '123456', '535923024@qq.com', '15678259451', 1, 0); 158 | INSERT INTO `mall_users` VALUES ('abc-126', 'Jen', '123456', '635423024@qq.com', '17678250451', 1, 0); 159 | INSERT INTO `mall_users` VALUES ('abc-127', 'His', '123456', '735523024@qq.com', '17632459451', 1000, 1); 160 | INSERT INTO `mall_users` VALUES ('d73e1167acc1451dba150ad7ae255eee', 'editDialo', 'editDialo', 'editDialo@qq.com', '13678956875', NULL, 0); 161 | INSERT INTO `mall_users` VALUES ('e26eb1c4693e412ab7e415356cab291a', 'samous', '123456', '1456987545@qq.com', '13878454578', NULL, 0); 162 | INSERT INTO `mall_users` VALUES ('f0164dad6dd94540899455aed267938d', 'gVisible', 'editDialogVi', 'editDialo1@qq.com', '13878955678', NULL, 0); 163 | 164 | -- ---------------------------- 165 | -- Table structure for roles_powers 166 | -- ---------------------------- 167 | DROP TABLE IF EXISTS `roles_powers`; 168 | CREATE TABLE `roles_powers` ( 169 | `roles_id` int(11) NOT NULL, 170 | `powers_id` int(11) NOT NULL 171 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 172 | 173 | -- ---------------------------- 174 | -- Records of roles_powers 175 | -- ---------------------------- 176 | INSERT INTO `roles_powers` VALUES (1000, 202); 177 | INSERT INTO `roles_powers` VALUES (1000, 203); 178 | INSERT INTO `roles_powers` VALUES (1000, 204); 179 | INSERT INTO `roles_powers` VALUES (1000, 101); 180 | INSERT INTO `roles_powers` VALUES (1000, 201); 181 | INSERT INTO `roles_powers` VALUES (1000, 205); 182 | INSERT INTO `roles_powers` VALUES (1000, 206); 183 | INSERT INTO `roles_powers` VALUES (1000, 207); 184 | INSERT INTO `roles_powers` VALUES (1000, 208); 185 | INSERT INTO `roles_powers` VALUES (1000, 302); 186 | INSERT INTO `roles_powers` VALUES (1000, 303); 187 | INSERT INTO `roles_powers` VALUES (1000, 304); 188 | INSERT INTO `roles_powers` VALUES (1000, 305); 189 | INSERT INTO `roles_powers` VALUES (1000, 403); 190 | INSERT INTO `roles_powers` VALUES (1000, 405); 191 | INSERT INTO `roles_powers` VALUES (1000, 406); 192 | INSERT INTO `roles_powers` VALUES (1000, 407); 193 | INSERT INTO `roles_powers` VALUES (1002, 201); 194 | INSERT INTO `roles_powers` VALUES (1002, 202); 195 | INSERT INTO `roles_powers` VALUES (1002, 203); 196 | INSERT INTO `roles_powers` VALUES (1002, 204); 197 | INSERT INTO `roles_powers` VALUES (1002, 205); 198 | INSERT INTO `roles_powers` VALUES (1002, 206); 199 | INSERT INTO `roles_powers` VALUES (1002, 207); 200 | INSERT INTO `roles_powers` VALUES (1002, 208); 201 | INSERT INTO `roles_powers` VALUES (1002, 302); 202 | INSERT INTO `roles_powers` VALUES (1002, 303); 203 | INSERT INTO `roles_powers` VALUES (1002, 304); 204 | INSERT INTO `roles_powers` VALUES (1002, 305); 205 | INSERT INTO `roles_powers` VALUES (1002, 405); 206 | INSERT INTO `roles_powers` VALUES (1002, 406); 207 | INSERT INTO `roles_powers` VALUES (1002, 806); 208 | INSERT INTO `roles_powers` VALUES (1002, 101); 209 | INSERT INTO `roles_powers` VALUES (1002, 403); 210 | INSERT INTO `roles_powers` VALUES (1002, 102); 211 | INSERT INTO `roles_powers` VALUES (1002, 807); 212 | INSERT INTO `roles_powers` VALUES (1001, 203); 213 | INSERT INTO `roles_powers` VALUES (1001, 303); 214 | INSERT INTO `roles_powers` VALUES (1001, 101); 215 | INSERT INTO `roles_powers` VALUES (1001, 201); 216 | INSERT INTO `roles_powers` VALUES (1001, 302); 217 | INSERT INTO `roles_powers` VALUES (2, 202); 218 | INSERT INTO `roles_powers` VALUES (2, 203); 219 | INSERT INTO `roles_powers` VALUES (2, 204); 220 | INSERT INTO `roles_powers` VALUES (2, 208); 221 | INSERT INTO `roles_powers` VALUES (2, 302); 222 | INSERT INTO `roles_powers` VALUES (2, 303); 223 | INSERT INTO `roles_powers` VALUES (2, 304); 224 | INSERT INTO `roles_powers` VALUES (2, 305); 225 | INSERT INTO `roles_powers` VALUES (2, 403); 226 | INSERT INTO `roles_powers` VALUES (2, 405); 227 | INSERT INTO `roles_powers` VALUES (2, 406); 228 | INSERT INTO `roles_powers` VALUES (2, 407); 229 | INSERT INTO `roles_powers` VALUES (2, 104); 230 | INSERT INTO `roles_powers` VALUES (2, 605); 231 | INSERT INTO `roles_powers` VALUES (2, 606); 232 | INSERT INTO `roles_powers` VALUES (2, 607); 233 | INSERT INTO `roles_powers` VALUES (2, 608); 234 | INSERT INTO `roles_powers` VALUES (2, 609); 235 | INSERT INTO `roles_powers` VALUES (2, 610); 236 | INSERT INTO `roles_powers` VALUES (2, 611); 237 | INSERT INTO `roles_powers` VALUES (2, 612); 238 | INSERT INTO `roles_powers` VALUES (2, 613); 239 | INSERT INTO `roles_powers` VALUES (2, 706); 240 | INSERT INTO `roles_powers` VALUES (2, 708); 241 | INSERT INTO `roles_powers` VALUES (2, 101); 242 | INSERT INTO `roles_powers` VALUES (2, 201); 243 | 244 | SET FOREIGN_KEY_CHECKS = 1; 245 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 电商后台管理系统(Springboot-vue) 2 | 3 | [Demo Site](http://43.226.35.120:8081/)
4 | [My Blog](https://coderblue.cn/) 5 | 6 | 7 | 由于部署在的服务器非主流的,运行起来比较缓慢。而且经常代码没问题,但是就是无法请求。有点怀疑宝塔部署的nginx不太稳定,一刷新页面就404错误了。后续如果时间充足,准备改到阿里云服务器,用nginx反向代理转发到我的子域名吧。 8 | ### 功能 9 | 10 | > 用于管理用户账号,商品分类,商品信息,订单,数据统计等业务功能 11 | 12 | 13 | ### 开发模式 14 | 15 | > 电商后台管理系统整体采用前后端分离的开发模式,其中前端项目是基于 Vue 技术栈的 SPA 项目 16 | 17 | ![](https://img-blog.csdnimg.cn/20200505224259629.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNDc2NDY1,size_16,color_FFFFFF,t_70) 18 | 19 | ### 技术选型 20 | 21 | #### 前端项目技术栈 22 | 23 | - Vue 24 | - Vue-router 25 | - Element-UI 26 | - Axios 27 | - Echarts 28 | 29 | #### 后端项目技术栈 30 | 31 | - Springboot 32 | - Mysql8.0(开始用的 Oracle,在部署服务器的时候遂更改) 33 | - Mybatis 34 | 35 | #### Api接口 36 | - 百度人脸识别 37 | 38 | ### 项目初始化 39 | 40 | #### 前端项目初始化步骤 41 | 42 | 1. 安装 Vue 脚手架 43 | 2. 通过 Vue-Cli 创建项目 44 | 3. 配置 Vue-router 45 | 4. 配置 Element-UI 组件库 46 | 5. 配置 Axios 库 47 | 6. 初始化 git 远程仓库 48 | 49 | 50 | #### 人脸识别简易使用 51 | 52 | 1.工具包准备 53 | ```java 54 | // FileUtil,Base64Util,HttpUtil,GsonUtils请从 55 | https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72 56 | https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2 57 | https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3 58 | https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3 59 | ``` 60 | 61 | 2.获取token 62 | ```java 63 | package cn.blue.mall.service.impl; 64 | 65 | /** 66 | * @author Blue 67 | * @date 2020/5/4 68 | **/ 69 | 70 | 71 | import cn.blue.mall.consts.FaceConst; 72 | import org.json.JSONObject; 73 | 74 | import java.io.BufferedReader; 75 | import java.io.InputStreamReader; 76 | import java.net.HttpURLConnection; 77 | import java.net.URL; 78 | import java.util.List; 79 | import java.util.Map; 80 | 81 | /** 82 | * 获取token类 83 | * @author Blue 84 | */ 85 | public class AuthServiceImpl { 86 | 87 | /** 88 | * 获取权限token 89 | * @return 返回示例: 90 | * { 91 | * "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567", 92 | * "expires_in": 2592000 93 | * } 94 | */ 95 | public static String getAuth() { 96 | // 官网获取的 API Key 更新为你注册的 97 | String clientId = FaceConst.CLIENT_ID; 98 | // 官网获取的 Secret Key 更新为你注册的 99 | String clientSecret = FaceConst.CLIENT_SECRET; 100 | return getAuth(clientId, clientSecret); 101 | } 102 | 103 | /** 104 | * 获取API访问token 105 | * 该token有一定的有效期,需要自行管理,当失效时需重新获取. 106 | * @param ak - 百度云官网获取的 API Key 107 | * @param sk - 百度云官网获取的 Securet Key 108 | * @return assess_token 示例: 109 | * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567" 110 | */ 111 | public static String getAuth(String ak, String sk) { 112 | // 获取token地址 113 | String authHost = "https://aip.baidubce.com/oauth/2.0/token?"; 114 | String getAccessTokenUrl = authHost 115 | // 1. grant_type为固定参数 116 | + "grant_type=client_credentials" 117 | // 2. 官网获取的 API Key 118 | + "&client_id=" + ak 119 | // 3. 官网获取的 Secret Key 120 | + "&client_secret=" + sk; 121 | try { 122 | URL realUrl = new URL(getAccessTokenUrl); 123 | // 打开和URL之间的连接 124 | HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); 125 | connection.setRequestMethod("GET"); 126 | connection.connect(); 127 | // 获取所有响应头字段 128 | Map> map = connection.getHeaderFields(); 129 | // 遍历所有的响应头字段 130 | for (String key : map.keySet()) { 131 | System.err.println(key + "--->" + map.get(key)); 132 | } 133 | // 定义 BufferedReader输入流来读取URL的响应 134 | BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 135 | String result = ""; 136 | String line; 137 | while ((line = in.readLine()) != null) { 138 | result += line; 139 | } 140 | /** 141 | * 返回结果示例 142 | */ 143 | System.err.println("result:" + result); 144 | JSONObject jsonObject = new JSONObject(result); 145 | String access_token = jsonObject.getString("access_token"); 146 | return access_token; 147 | } catch (Exception e) { 148 | System.err.printf("获取token失败!"); 149 | e.printStackTrace(System.err); 150 | } 151 | return null; 152 | } 153 | 154 | } 155 | ``` 156 | 157 | 3.人脸检测 158 | ```java 159 | package cn.blue.mall.utils; 160 | 161 | import cn.blue.mall.service.impl.AuthServiceImpl; 162 | 163 | import java.io.File; 164 | import java.util.HashMap; 165 | import java.util.Map; 166 | 167 | /** 168 | * 人脸检测与属性分析 169 | * @author Blue 170 | */ 171 | public class FaceDetect { 172 | 173 | public static String faceDetect(String filePath) { 174 | // filePath 文件路径 175 | File file = new File(filePath); 176 | // 请求url 177 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"; 178 | try { 179 | Map map = new HashMap<>(); 180 | map.put("image", Base64Util.encode(FileUtil.readFileByBytes(filePath))); 181 | // 返回的参数信息之间不要有空格,pic必须要有face 182 | map.put("face_field", "age,beauty,expression,face_shape,gender,glasses,race,quality,eye_status,emotion,face_type,location"); 183 | map.put("image_type", "BASE64"); 184 | String param = GsonUtils.toJson(map); 185 | 186 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 187 | String accessToken = AuthServiceImpl.getAuth(); 188 | String result = HttpUtil.post(url, accessToken, "application/json", param); 189 | System.out.println(result); 190 | return result; 191 | } catch (Exception e) { 192 | e.printStackTrace(); 193 | } 194 | return null; 195 | } 196 | 197 | } 198 | ``` 199 | 200 | 4.利用返回的Json串生成实体类(按需要导入即可):[Json串生成Java实体类工具](http://www.bejson.com/json2javapojo/new/) 201 | 202 | ![](https://img-blog.csdnimg.cn/20200505183604561.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNDc2NDY1,size_16,color_FFFFFF,t_70) 203 | 204 | 5.人脸搜索 205 | ```java 206 | package cn.blue.mall.utils; 207 | 208 | import cn.blue.mall.consts.FaceConst; 209 | import cn.blue.mall.service.impl.AuthServiceImpl; 210 | 211 | import java.io.File; 212 | import java.util.*; 213 | 214 | /** 215 | * 人脸搜索 216 | * @author Blue 217 | */ 218 | public class FaceSearch { 219 | 220 | public static String faceSearch(String filePath) { 221 | // 请求url 222 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/search"; 223 | File file = new File(filePath); 224 | try { 225 | Map map = new HashMap<>(); 226 | map.put("image", Base64Util.encode(FileUtil.readFileByBytes(filePath))); 227 | map.put("liveness_control", "NONE"); 228 | map.put("group_id_list", FaceConst.GROUP_ID); 229 | map.put("image_type", "BASE64"); 230 | map.put("quality_control", "LOW"); 231 | 232 | String param = GsonUtils.toJson(map); 233 | 234 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 235 | String accessToken = AuthServiceImpl.getAuth(); 236 | 237 | String result = HttpUtil.post(url, accessToken, "application/json", param); 238 | System.out.println(result); 239 | return result; 240 | } catch (Exception e) { 241 | e.printStackTrace(); 242 | } 243 | return null; 244 | } 245 | 246 | } 247 | ``` 248 | 249 | 6.人脸注册 250 | ```java 251 | package cn.blue.mall.utils; 252 | 253 | import cn.blue.mall.consts.FaceConst; 254 | import cn.blue.mall.service.impl.AuthServiceImpl; 255 | 256 | import java.util.HashMap; 257 | import java.util.Map; 258 | import java.util.UUID; 259 | 260 | /** 261 | * 人脸注册 262 | * @author Blue 263 | */ 264 | public class FaceAdd { 265 | 266 | public static String faceAdd(String filePath) { 267 | // 请求url 268 | String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"; 269 | try { 270 | Map map = new HashMap<>(); 271 | map.put("image", Base64Util.encode(FileUtil.readFileByBytes(filePath))); 272 | String userId = UUID.randomUUID().toString().replace("-", "").substring(16) + System.currentTimeMillis(); 273 | map.put("group_id", FaceConst.GROUP_ID); 274 | map.put("user_id", userId); 275 | map.put("user_info", "abc"); 276 | map.put("liveness_control", "NONE"); 277 | map.put("image_type", "BASE64"); 278 | map.put("quality_control", "LOW"); 279 | 280 | String param = GsonUtils.toJson(map); 281 | 282 | // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 283 | String accessToken = AuthServiceImpl.getAuth(); 284 | 285 | String result = HttpUtil.post(url, accessToken, "application/json", param); 286 | System.out.println(result); 287 | return result; 288 | } catch (Exception e) { 289 | e.printStackTrace(); 290 | } 291 | return null; 292 | } 293 | } 294 | ``` 295 | 296 | 7.功能测试,推荐先使用junit5单元测试 297 | ```java 298 | class FaceSearchTest { 299 | 300 | @Test 301 | void faceSearch() { 302 | // 上传的图片不宜太大了,不然不好处理。 303 | String resultJson = FaceSearch.faceSearch("D:\\pythonDemo\\8.jpg"); 304 | FaceInfo faceInfo = GsonUtils.fromJson(resultJson, FaceInfo.class); 305 | System.err.println("人脸搜索:" + faceInfo.getResult().getUser_list().get(0).getScore()); 306 | } 307 | } 308 | ``` 309 | 310 | 8.对前端传过来的base64处理转换成图片 311 | ```java 312 | BASE64Decoder decoder = new BASE64Decoder(); 313 | String imgFilePath = FaceConst.PATH_PRE + System.currentTimeMillis() + FaceConst.PATH_SUF; 314 | try (OutputStream out = new FileOutputStream(imgFilePath)) { 315 | // Base64解码 生成jpeg图片 316 | byte[] decoderBytes = decoder.decodeBuffer(base64.split(",")[1]); 317 | // 写入到磁盘指定地方 318 | out.write(decoderBytes); 319 | } 320 | ``` 321 | 322 | 9.定量清理图片 323 | ```java 324 | File file = new File(FaceConst.PATH_PRE); 325 | // 判断file是否是文件目录 若是返回TRUE 326 | if (file.isDirectory()) { 327 | // name存储file文件夹中的文件名 328 | String name[] = file.list(); 329 | for (int i = 0; i < name.length; i++) { 330 | // 此时就可得到文件夹中的文件 331 | File f = new File(FaceConst.PATH_PRE, name[i]); 332 | // 删除文件 333 | f.delete(); 334 | } 335 | } 336 | ``` 337 | 338 | 10.引入相关依赖 339 | ```xml 340 | 341 | 342 | com.google.code.gson 343 | gson 344 | 2.8.5 345 | 346 | 347 | 348 | com.vaadin.external.google 349 | android-json 350 | 0.0.20131108.vaadin1 351 | compile 352 | 353 | ``` 354 | 355 | 11.简易效果图 356 | ![](https://img-blog.csdnimg.cn/20200505224218347.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNDc2NDY1,size_16,color_FFFFFF,t_70) 357 | 358 | ![](https://img-blog.csdnimg.cn/20200505183512315.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNDc2NDY1,size_16,color_FFFFFF,t_70) 359 | 360 | 361 | [更多功能参考百度人脸识别Api文档即可](https://cloud.baidu.com/doc/FACE/s/yk37c1u4t) 362 | 363 | #### 后端项目的环境安装配置 364 | 365 | 1. 安装 MySQL8.0 数据库 366 | 2. 数据库表:[数据库代码文件](./mall_vue.sql) 367 | 368 | - 创建电商商品表 369 | 370 | ```sql 371 | CREATE TABLE `mall_goods` ( 372 | `id` int(11) NOT NULL, 373 | `cat_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 374 | `cat_deleted` int(255) NOT NULL, 375 | `cat_level` int(255) NOT NULL, 376 | `cat_pid` int(11) NOT NULL, 377 | PRIMARY KEY (`id`) USING BTREE 378 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 379 | ``` 380 | 381 | - 创建电商权限表 382 | 383 | ```sql 384 | CREATE TABLE `mall_powers` ( 385 | `id` int(11) NOT NULL, 386 | `auth_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 387 | `grade` int(255) NOT NULL, 388 | `pid` int(11) NULL DEFAULT NULL, 389 | `path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 390 | PRIMARY KEY (`id`) USING BTREE 391 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 392 | ``` 393 | 394 | - 创建用户角色表 395 | 396 | ```sql 397 | CREATE TABLE `mall_roles` ( 398 | `id` int(11) NULL DEFAULT NULL, 399 | `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 400 | `role_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL 401 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 402 | ``` 403 | 404 | - 405 | 406 | ```sql 用户表 407 | CREATE TABLE `mall_users` ( 408 | `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 409 | `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 410 | `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 411 | `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 412 | `telephone` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 413 | `role` int(255) NULL DEFAULT NULL, 414 | `status` int(255) NULL DEFAULT 0, 415 | PRIMARY KEY (`id`) USING BTREE 416 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 417 | ``` 418 | 419 | - 角色权限的中间表 420 | 421 | ```sql 422 | CREATE TABLE `roles_powers` ( 423 | `roles_id` int(11) NOT NULL, 424 | `powers_id` int(11) NOT NULL 425 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 426 | ``` 427 | 428 | 3. 使用 Postman 测试后台项目接口是否正常 429 | ![](https://img-blog.csdnimg.cn/2020031817462317.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNDc2NDY1,size_16,color_FFFFFF,t_70) 430 | 431 | 4. 创建 idea 的 springboot 工程,导入相关依赖 432 | 433 | ```xml 434 | 435 | org.springframework.boot 436 | spring-boot-starter-web 437 | 438 | 439 | org.springframework.security 440 | spring-security-web 441 | 442 | 443 | org.springframework.security 444 | spring-security-config 445 | 446 | 447 | org.springframework.boot 448 | spring-boot-devtools 449 | runtime 450 | true 451 | 452 | 453 | org.projectlombok 454 | lombok 455 | true 456 | 457 | 458 | org.mybatis.spring.boot 459 | mybatis-spring-boot-starter 460 | 2.1.1 461 | 462 | 463 | com.alibaba 464 | druid 465 | 1.1.20 466 | 467 | 468 | com.github.pagehelper 469 | pagehelper-spring-boot-starter 470 | 1.2.12 471 | 472 | 473 | org.apache.logging.log4j.adapters 474 | log4j-to-slf4j 475 | 2.0-beta4 476 | 477 | 478 | mysql 479 | mysql-connector-java 480 | runtime 481 | 482 | 483 | 484 | com.google.code.gson 485 | gson 486 | 2.8.5 487 | 488 | 489 | 490 | com.vaadin.external.google 491 | android-json 492 | 0.0.20131108.vaadin1 493 | compile 494 | 495 | 496 | org.springframework.boot 497 | spring-boot-starter-test 498 | test 499 | 500 | 501 | org.junit.vintage 502 | junit-vintage-engine 503 | 504 | 505 | 506 | 507 | ``` 508 | 5. 注意:本地访问路径- localhost:8081/index.html,如有弹窗:用户名默认user,密码在控制台生成的 509 | 510 | ### 登录概述 511 | 512 | #### 登录业务流程 513 | 514 | 1. 在登录页面输入用户名和密码 515 | 2. 调用后台接口进行验证 516 | 3. 通过验证之后,根据后台的响应状态跳转到项目主页 517 | 518 | #### 登录业务相关技术点 519 | 520 | 1. http 是无状态的 521 | 2. 通过 cookie 在客户端记录状态 522 | 3. 通过 sesion 在服务器端记录状态 523 | 4. 通过 token 维持状态(允许跨域使用) 524 | 525 | 526 | #### 登录业务流程 527 | 528 | ##### 登录页面的布局 529 | 530 | 通过 Element-UI 组件实现布局 531 | 532 | - el-form 533 | - el-form-item 534 | - el-input 535 | - el-button 536 | - 字体图标 537 | 538 | ##### 创建 git 分支 539 | 540 | ``` 541 | // 创建并切换登录分支 542 | git checkout -b login 543 | 544 | // login分支合并到主分支 545 | // 1.切换到master分支 546 | git checkout master 547 | // 2.合并分支到master 548 | git merge login 549 | 550 | // 将本地login子分支推送到github 551 | git push -u origin login 552 | ``` 553 | 554 | ##### 路由导航守卫控制访问权限 555 | 556 | > 如果用户没有登录,但是直接通过 URL 访问特定页面,需要重新导航到登录页面 557 | 558 | ```js 559 | //为路由对象,添加beforeEach导航守卫 560 | router.beforeEach((to, from, next) => { 561 | //如果用户访问的登录页,直接放行 562 | if (to.path === "login") return next(); 563 | //从sessionStorage中获取到保存的token值 564 | const tokenStr = window.sessionStorage.getItem("token"); 565 | //如果么有token,强制跳转到登录页 566 | if (!tokenStr) return next("/login"); 567 | next(); 568 | }); 569 | ``` 570 | 571 | ### 主页布局 572 | 573 | #### 通过接口获取菜单数据 574 | 575 | > 通过 axios 请求拦截器添加 token,保证拥有获取数据的权限 576 | 577 | ```js 578 | // axios请求拦截 579 | axios.interceptors.request.use(config => { 580 | // 为请求头对象,添加token验证的Authorization字段 581 | config.headers.Authorization = window.sessionStorage.getItem("token"); 582 | return config; 583 | }); 584 | ``` 585 | 586 | ### 用户管理 587 | >通过用户管理管理各个用户间的信息,还可以为其分配角色权限 588 | 589 | 用户列表 590 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/yonghu.png) 591 | 592 | 用户编辑 593 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/yonghu1.png) 594 | 等... 595 | 596 | ### 权限管理 597 | 598 | #### 权限管理业务分析 599 | 600 | > 通过权限管理模块控制不同的用户可以进行哪些操作,具体可以通过角色的方式进行控制,即每个用户分配一个特定的角色,角色包括不同的功能权限 601 | 602 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/quanxian.png) 603 | 604 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/quanxian1.png) 605 | 606 | 607 | ### 分类管理 608 | 609 | #### 商品分类概述 610 | 611 | > 商品分类用于在购物时,快速找到需要购买的商品,进行直观显示 612 | 613 | ### 参数管理 614 | 615 | #### 参数管理概述 616 | 617 | > 商品参数用于显示商品的特征信息,可以通过电商平台详情页面直观的看到 618 | 619 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/fenlei.png) 620 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/fenlei1.png) 621 | 622 | ### 数据统计 623 | 624 | 旨在熟悉Echarts可视化图表的使用 625 | #### 模拟二月份疫情图 626 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/shuju.png) 627 | 628 | ### 订单管理 629 | 630 | ![](https://cdn.jsdelivr.net/gh/onecoderly/cdn/mall/dingdan.png) 631 | 632 | 633 | ### 项目所用依赖(vue 全家桶不描述) 634 | 635 | 1. 运行依赖 636 | 637 | - axios => 发送请求 638 | - echarts => 图表 639 | - element-ui => element ui 组件 640 | - lodash => js 工具库,该项目用到深拷贝与对象合并 641 | - moment => 时间处理工具库 642 | - nprogress => 进度条库 643 | - v-viewer => 图片预览工具库 644 | - vue-quill-editor => 富文本编辑器 645 | - vue-table-with-tree-grid => 树形菜单/表格 646 | 647 | 2. 开发依赖 648 | 649 | - babel => es6+语法转换 650 | - eslint/babel-eslint => 语法检查 651 | - less/less-loader => less 语法 652 | - babel-plugin-transform-remove-console => 移除 console 插件 653 | 654 | ### 项目优化 655 | 656 | ### 项目优化策略 657 | 658 | - 生成打包报告 659 | 660 | - 通过命令行参数形式生成报告=>vue-cli-service build --report 661 | - 通过可视化 ui 面板直接查看报告(通过控制台和分析面板) 662 | 663 | - 通过 vue.config.js 修改 webpack 的默认配置 664 | 665 | > 通过 vue-cli 3.0 工具生成的项目,默认隐藏了所有 webpack 的配置项,目的是为了屏蔽项目的配置过程,让开发人员把工作的 重心,放在具体功能和业务逻辑的实现上 666 | 667 | - 为开发模式与发布模式指定不同的打包入口 668 | 669 | > 默认情况下,vue 项目的开发与发布模式,共用同一个打包的入口文件(即 src/main.js),为了将项目的开发过程与发布过程分离,可以为两种模式,各自指定打包的入口文件,即: 670 | > 671 | > 1. 开发模式入口文件 src/main-dev.js 672 | > 2. 发布模式入口文件 src/main-prod.js 673 | > 674 | > 方案:configureWebpack(通过链式编程形式)和 chainWebpack(通过操作对象形式) 675 | > 676 | > 在 vue.config.js 导出的配置文件中,新增 configureWebpack 或 chainWebpack 节点,来自定义 webpack 的打包配置 677 | 678 | ```js 679 | // 代码示例 680 | module.exports = { 681 | chainWebpack: config => { 682 | // 发布模式 683 | config.when(process.env.NODE_ENV === "production", config => { 684 | config 685 | .entry("app") 686 | .clear() 687 | .add("./src/main-prod.js"); 688 | }); 689 | // 开发模式 690 | config.when(process.env.NODE_ENV === "development", config => { 691 | config 692 | .entry("app") 693 | .clear() 694 | .add("./src/main-dev.js"); 695 | }); 696 | } 697 | }; 698 | ``` 699 | 700 | - 第三方库启用 CDN 701 | 702 | - 通过 externals 加载外部 cdn 资源 703 | 704 | > 默认情况下,通过 import 语法导入的第三方依赖包,最终会打包合并到同一个文件中,从而导致打包成功后,单文件体积过大的问题 => **chunk-vendors**体积过大 705 | > 706 | > 为了解决上述问题,可以通过 webpack 的 externals 节点,来配置加载外部的 cdn 资源,凡是声明在 externals 中的第三方依赖包,都不会被打包 707 | 708 | 1. 步骤 1 709 | 710 | ```js 711 | module.exports = { 712 | chainWebpack: config => { 713 | config.when(process.env.NODE_ENV === "production", config => { 714 | config 715 | .entry("app") 716 | .clear() 717 | .add("./src/main-prod.js"); 718 | // 在vue.config.js如下配置 719 | config.set("externals", { 720 | vue: "Vue", 721 | "vue-router": "VueRouter", 722 | axios: "axios", 723 | lodash: "_", 724 | echarts: "echarts", 725 | nporgress: "NProgress", 726 | "vue-quill-editor": "VueQuillEditor" 727 | }); 728 | }); 729 | config.when(process.env.NODE_ENV === "development", config => { 730 | config 731 | .entry("app") 732 | .clear() 733 | .add("./src/main-dev.js"); 734 | }); 735 | } 736 | }; 737 | ``` 738 | 739 | 2. 步骤 2 740 | 741 | > 在 public/index.html 文件头部,将 main-prod 中的已经进行配置的 import(样式表)删除替换为 cdn 引入 742 | 743 | ```css 744 | 745 | 746 | ​ 747 | 748 | ​ 749 | 750 | ​ 751 | 752 | ​ 753 | 754 | ​ 755 | ``` 756 | 757 | 3. 步骤 3 758 | 759 | > 在 public/index.html 文件头部,将 main-prod 中的已经进行配置的 import(js 文件)删除替换为 cdn 引入 760 | 761 | ```js 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | ``` 773 | 4. cdn 加速前后对比( **chunk-vendors**打包文件) 774 | 775 | > Parsed 大小 2.6m=> **596.9kB** 776 | 777 | - 使用 cdn 优化 elementui 打包 778 | 779 | > 具体操作流程 780 | > 781 | > 1. 在 main-prod.js 中,注释掉 element-ui 按需加载的代码 782 | > 2. 在 index.html 头部区域中,通过 cdn 加载 element-ui 的 js 和 css 样式 783 | > 784 | > 785 | > 786 | > 787 | 788 | - 首页内容定制 789 | 790 | > 不同打包环境下,首页内容可能会有所不同,通过插件方式定制 791 | 792 | - vue.config.js 配置 793 | 794 | ```js 795 | config.plugin("html").tap(args => { 796 | args[0].isProd = true或false; 797 | return args; 798 | }); 799 | ``` 800 | 801 | - index.html 修改 802 | 803 | ```html 804 | 805 | <%= htmlWebpackPlugin.options.isProd ? '' : 'dev-' %>vue-mall 806 | <% if(htmlWebpackPlugin.options.isProd) { %> css | js放在这儿 <% } %> 807 | ``` 808 | 809 | - Element-UI 组件按需加载 810 | 811 | - 路由懒加载 812 | 813 | > 在打包构建项目时,javascript 包会变得特别大,影响页面加载,如果我们能把不同路由对应的组件分隔成不同的代码块,然后当路由被访问的时候才加载对应组件,这样更加高效 814 | 815 | - 安装@babel/plugin-syntax-dynamic-import 包 816 | - 在 babel.config.js 配置文件声明该插件 817 | - 将路由改为按需加载形式 818 | 819 | ```js 820 | // 示例: 821 | const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') 822 | const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') 823 | const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue') 824 | 825 | // import Login from '../components/Login.vue' 826 | const Login = () => import(/* webpackChunkName: "login_home_welcome" */ '../components/Login.vue') 827 | // import Home from '../components/Home.vue' 828 | const Home = () => import(/* webpackChunkName: "login_home_welcome" */ '../components/Home.vue') 829 | // import Welcome from '../components/Welcome.vue' 830 | const Welcome = () => import(/* webpackChunkName: "login_home_welcome" */ '../components/Welcome.vue') 831 | ... 832 | ``` 833 | 834 | #### 配置 https 服务 835 | 836 | ##### 为什么要启用 https 服务 837 | 838 | - 传统的 http 协议传输的数据都是明文,不安全 839 | - 采用 https 协议对传输的数据进行了加密处理,可以防止数据被中间人窃取,使用更安全 840 | 841 | 申请 ssl 证书(https://freessl.org) => 正常企业还是使用收费 ssh(http 协议默认运行在 80 端口,https 默认运行在 443 端口) 842 | 843 | ``` 844 | --- 845 | 846 | [接口API](./api接口文档.md) 847 | 848 | [vue.config.js配置](https://cli.vuejs.org/zh/config/#lintonsave) 849 | 850 | [路由懒加载](https://router.vuejs.org/zh/guide/advanced/lazy-loading.html) 851 | 852 | [babel配置](https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import/) 853 | ``` 854 | -------------------------------------------------------------------------------- /api接口文档.md: -------------------------------------------------------------------------------- 1 | # 1. 电商管理后台 API 接口文档 2 | 3 | ## 1.1. API V1 接口说明 4 | 5 | - 接口基准地址:`http://127.0.0.1:8888/api/private/v1/` 6 | - 服务端已开启 CORS 跨域支持 7 | - API V1 认证统一使用 Token 认证 8 | - 需要授权的 API ,必须在请求头中使用 `Authorization` 字段提供 `token` 令牌 9 | - 使用 HTTP Status Code 标识状态 10 | - 数据返回格式统一使用 JSON 11 | 12 | ### 1.1.1. 支持的请求方法 13 | 14 | - GET(SELECT):从服务器取出资源(一项或多项)。 15 | - POST(CREATE):在服务器新建一个资源。 16 | - PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。 17 | - PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。 18 | - DELETE(DELETE):从服务器删除资源。 19 | - HEAD:获取资源的元数据。 20 | - OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。 21 | 22 | ### 1.1.2. 通用返回状态说明 23 | 24 | | *状态码* | *含义* | *说明* | 25 | | -------- | --------------------- | --------------------------------------------------- | 26 | | 200 | OK | 请求成功 | 27 | | 201 | CREATED | 创建成功 | 28 | | 204 | DELETED | 删除成功 | 29 | | 400 | BAD REQUEST | 请求的地址不存在或者包含不支持的参数 | 30 | | 401 | UNAUTHORIZED | 未授权 | 31 | | 403 | FORBIDDEN | 被禁止访问 | 32 | | 404 | NOT FOUND | 请求的资源不存在 | 33 | | 422 | Unprocesable entity | [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误 | 34 | | 500 | INTERNAL SERVER ERROR | 内部错误 | 35 | | | | | 36 | 37 | ------ 38 | 39 | ## 1.2. 登录 40 | 41 | ### 1.2.1. 登录验证接口 42 | 43 | - 请求路径:login 44 | - 请求方法:post 45 | - 请求参数 46 | 47 | | 参数名 | 参数说明 | 备注 | 48 | | -------- | -------- | -------- | 49 | | username | 用户名 | 不能为空 | 50 | | password | 密码 | 不能为空 | 51 | 52 | - 响应参数 53 | 54 | | 参数名 | 参数说明 | 备注 | 55 | | -------- | ----------- | --------------- | 56 | | id | 用户 ID | | 57 | | rid | 用户角色 ID | | 58 | | username | 用户名 | | 59 | | mobile | 手机号 | | 60 | | email | 邮箱 | | 61 | | token | 令牌 | 基于 jwt 的令牌 | 62 | 63 | - 响应数据 64 | 65 | ```json 66 | { 67 | "data": { 68 | "id": 500, 69 | "rid": 0, 70 | "username": "admin", 71 | "mobile": "123", 72 | "email": "123@qq.com", 73 | "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjUwMCwicmlkIjowLCJpYXQiOjE1MTI1NDQyOTksImV4cCI6MTUxMjYzMDY5OX0.eGrsrvwHm-tPsO9r_pxHIQ5i5L1kX9RX444uwnRGaIM" 74 | }, 75 | "meta": { 76 | "msg": "登录成功", 77 | "status": 200 78 | } 79 | } 80 | ``` 81 | 82 | ## 1.3. 用户管理 83 | 84 | ### 1.3.1. 用户数据列表 85 | 86 | - 请求路径:users 87 | - 请求方法:get 88 | - 请求参数 89 | 90 | | 参数名 | 参数说明 | 备注 | 91 | | -------- | ------------ | -------- | 92 | | query | 查询参数 | 可以为空 | 93 | | pagenum | 当前页码 | 不能为空 | 94 | | pagesize | 每页显示条数 | 不能为空 | 95 | 96 | - 响应参数 97 | 98 | | 参数名 | 参数说明 | 备注 | 99 | | --------- | ------------ | ---- | 100 | | totalpage | 总记录数 | | 101 | | pagenum | 当前页码 | | 102 | | users | 用户数据集合 | | 103 | 104 | - 响应数据 105 | 106 | ```json 107 | { 108 | "data": { 109 | "totalpage": 5, 110 | "pagenum": 4, 111 | "users": [ 112 | { 113 | "id": 25, 114 | "username": "tige117", 115 | "mobile": "18616358651", 116 | "type": 1, 117 | "email": "tige112@163.com", 118 | "create_time": "2017-11-09T20:36:26.000Z", 119 | "mg_state": true, // 当前用户的状态 120 | "role_name": "炒鸡管理员" 121 | } 122 | ] 123 | }, 124 | "meta": { 125 | "msg": "获取成功", 126 | "status": 200 127 | } 128 | } 129 | ``` 130 | 131 | ### 1.3.2. 添加用户 132 | 133 | - 请求路径:users 134 | - 请求方法:post 135 | - 请求参数 136 | 137 | | 参数名 | 参数说明 | 备注 | 138 | | -------- | -------- | -------- | 139 | | username | 用户名称 | 不能为空 | 140 | | password | 用户密码 | 不能为空 | 141 | | email | 邮箱 | 可以为空 | 142 | | mobile | 手机号 | 可以为空 | 143 | 144 | - 响应参数 145 | 146 | | 参数名 | 参数说明 | 备注 | 147 | | -------- | ----------- | ---- | 148 | | id | 用户 ID | | 149 | | rid | 用户角色 ID | | 150 | | username | 用户名 | | 151 | | mobile | 手机号 | | 152 | | email | 邮箱 | | 153 | 154 | - 响应数据 155 | 156 | ```json 157 | { 158 | "data": { 159 | "id": 28, 160 | "username": "tige1200", 161 | "mobile": "test", 162 | "type": 1, 163 | "openid": "", 164 | "email": "test@test.com", 165 | "create_time": "2017-11-10T03:47:13.533Z", 166 | "modify_time": null, 167 | "is_delete": false, 168 | "is_active": false 169 | }, 170 | "meta": { 171 | "msg": "用户创建成功", 172 | "status": 201 173 | } 174 | } 175 | ``` 176 | 177 | ### 1.3.3. 修改用户状态 178 | 179 | - 请求路径:users/:uId/state/:type 180 | - 请求方法:put 181 | - 请求参数 182 | 183 | | 参数名 | 参数说明 | 备注 | 184 | | ------ | -------- | ------------------------------------------- | 185 | | uId | 用户 ID | 不能为空`携带在url中` | 186 | | type | 用户状态 | 不能为空`携带在url中`,值为 true 或者 false | 187 | 188 | - 响应数据 189 | 190 | ```json 191 | { 192 | "data": { 193 | "id": 566, 194 | "rid": 30, 195 | "username": "admin", 196 | "mobile": "123456", 197 | "email": "bb@itcast.com", 198 | "mg_state": 0 199 | }, 200 | "meta": { 201 | "msg": "设置状态成功", 202 | "status": 200 203 | } 204 | } 205 | ``` 206 | 207 | ### 1.3.4. 根据 ID 查询用户信息 208 | 209 | - 请求路径:users/:id 210 | - 请求方法:get 211 | - 请求参数 212 | 213 | | 参数名 | 参数说明 | 备注 | 214 | | ------ | -------- | --------------------- | 215 | | id | 用户 ID | 不能为空`携带在url中` | 216 | 217 | - 响应参数 218 | 219 | | 参数名 | 参数说明 | 备注 | 220 | | ------- | -------- | ---- | 221 | | id | 用户 ID | | 222 | | role_id | 角色 ID | | 223 | | mobile | 手机号 | | 224 | | email | 邮箱 | | 225 | 226 | - 响应数据 227 | 228 | ```json 229 | { 230 | "data": { 231 | "id": 503, 232 | "username": "admin3", 233 | "role_id": 0, 234 | "mobile": "00000", 235 | "email": "new@new.com" 236 | }, 237 | "meta": { 238 | "msg": "查询成功", 239 | "status": 200 240 | } 241 | } 242 | ``` 243 | 244 | ### 1.3.5. 编辑用户提交 245 | 246 | - 请求路径:users/:id 247 | - 请求方法:put 248 | - 请求参数 249 | 250 | | 参数名 | 参数说明 | 备注 | 251 | | ------ | -------- | --------------------------- | 252 | | id | 用户 id | 不能为空 `参数是url参数:id` | 253 | | email | 邮箱 | 可以为空 | 254 | | mobile | 手机号 | 可以为空 | 255 | 256 | - 响应参数 257 | 258 | | 参数名 | 参数说明 | 备注 | 259 | | ------- | -------- | ---- | 260 | | id | 用户 ID | | 261 | | role_id | 角色 ID | | 262 | | mobile | 手机号 | | 263 | | email | 邮箱 | | 264 | 265 | - 响应数据 266 | 267 | ```json 268 | /* 200表示成功,500表示失败 */ 269 | { 270 | "data": { 271 | "id": 503, 272 | "username": "admin3", 273 | "role_id": 0, 274 | "mobile": "111", 275 | "email": "123@123.com" 276 | }, 277 | "meta": { 278 | "msg": "更新成功", 279 | "status": 200 280 | } 281 | } 282 | ``` 283 | 284 | ### 1.3.6. 删除单个用户 285 | 286 | - 请求路径:users/:id 287 | - 请求方法:delete 288 | - 请求参数 289 | 290 | | 参数名 | 参数说明 | 备注 | 291 | | ------ | -------- | -------------------------- | 292 | | id | 用户 id | 不能为空`参数是url参数:id` | 293 | 294 | - 响应参数 295 | - 响应数据 296 | 297 | ```json 298 | { 299 | "data": null, 300 | "meta": { 301 | "msg": "删除成功", 302 | "status": 200 303 | } 304 | } 305 | ``` 306 | 307 | ### 1.3.7. 分配用户角色 308 | 309 | - 请求路径:users/:id/role 310 | - 请求方法:put 311 | - 请求参数 312 | 313 | | 参数名 | 参数说明 | 备注 | 314 | | ------ | -------- | -------------------------- | 315 | | id | 用户 ID | 不能为空`参数是url参数:id` | 316 | | rid | 角色 id | 不能为空`参数body参数` | 317 | 318 | - 响应参数 319 | 320 | | 参数名 | 参数说明 | 备注 | 321 | | ------- | -------- | ---- | 322 | | id | 用户 ID | | 323 | | role_id | 角色 ID | | 324 | | mobile | 手机号 | | 325 | | email | 邮箱 | | 326 | 327 | - 响应数据 328 | 329 | ```json 330 | { 331 | "data": { 332 | "id": 508, 333 | "rid": "30", 334 | "username": "asdf1", 335 | "mobile": "123123", 336 | "email": "adfsa@qq.com" 337 | }, 338 | "meta": { 339 | "msg": "设置角色成功", 340 | "status": 200 341 | } 342 | } 343 | ``` 344 | 345 | ## 1.4. 权限管理 346 | 347 | ### 1.4.1. 所有权限列表 348 | 349 | - 请求路径:rights/:type 350 | - 请求方法:get 351 | - 请求参数 352 | 353 | | 参数名 | 参数说明 | 备注 | 354 | | ------ | -------- | ------------------------------------------------------------ | 355 | | type | 类型 | 值 list 或 tree , list 列表显示权限, tree 树状显示权限,`参数是url参数:type` | 356 | 357 | - 响应参数 358 | 359 | | 参数名 | 参数说明 | 备注 | 360 | | -------- | ------------ | ---- | 361 | | id | 权限 ID | | 362 | | authName | 权限说明 | | 363 | | level | 权限层级 | | 364 | | pid | 权限父 ID | | 365 | | path | 对应访问路径 | | 366 | 367 | - 响应数据 type=list 368 | 369 | ```json 370 | { 371 | "data": [ 372 | { 373 | "id": 101, 374 | "authName": "商品管理", 375 | "level": "0", 376 | "pid": 0, 377 | "path": null 378 | }, 379 | { 380 | "id": 102, 381 | "authName": "订单管理", 382 | "level": "0", 383 | "pid": 0, 384 | "path": null 385 | } 386 | ], 387 | "meta": { 388 | "msg": "获取权限列表成功", 389 | "status": 200 390 | } 391 | } 392 | ``` 393 | 394 | type=tree 395 | 396 | ```json 397 | { 398 | data: [ 399 | { 400 | id: 101, 401 | authName: '商品管理', 402 | path: null, 403 | pid: 0, 404 | children: [ 405 | { 406 | id: 104, 407 | authName: '商品列表', 408 | path: null, 409 | pid: 101, 410 | children: [ 411 | { 412 | id: 105, 413 | authName: '添加商品', 414 | path: null, 415 | pid: '104,101' 416 | } 417 | ] 418 | } 419 | ] 420 | } 421 | ], 422 | meta: { 423 | msg: '获取权限列表成功', 424 | status: 200 425 | } 426 | } 427 | ``` 428 | 429 | ### 1.4.2. 左侧菜单权限 430 | 431 | - 请求路径:menus 432 | - 请求方法:get 433 | - 响应数据 434 | 435 | ```json 436 | { 437 | "data": 438 | { 439 | "id": 101, 440 | "authName": "商品管理", 441 | "path": null, 442 | "children": [ 443 | { 444 | "id": 104, 445 | "authName": "商品列表", 446 | "path": null, 447 | "children": [] 448 | } 449 | ] 450 | } 451 | "meta": { 452 | "msg": "获取菜单列表成功", 453 | "status": 200 454 | } 455 | } 456 | ``` 457 | 458 | ## 1.5. 角色管理 459 | 460 | ### 1.5.1. 角色列表 461 | 462 | - 请求路径:roles 463 | 464 | - 请求方法:get 465 | 466 | - 响应数据说明 467 | 468 | + 第一层为角色信息 469 | 470 | - 第二层开始为权限说明,权限一共有 3 层权限 471 | - 最后一层权限,不包含 `children` 属性 472 | 473 | - 响应数据 474 | 475 | ```json 476 | { 477 | "data": [ 478 | { 479 | "id": 30, 480 | "roleName": "主管", 481 | "roleDesc": "技术负责人", 482 | "children": [ 483 | { 484 | "id": 101, 485 | "authName": "商品管理", 486 | "path": null, 487 | "children": [ 488 | { 489 | "id": 104, 490 | "authName": "商品列表", 491 | "path": null, 492 | "children": [ 493 | { 494 | "id": 105, 495 | "authName": "添加商品", 496 | "path": null 497 | } 498 | ] 499 | } 500 | ] 501 | } 502 | ] 503 | } 504 | ], 505 | "meta": { 506 | "msg": "获取成功", 507 | "status": 200 508 | } 509 | } 510 | ``` 511 | 512 | ### 1.5.2. 添加角色 513 | 514 | - 请求路径:roles 515 | - 请求方法:post 516 | - 请求参数 517 | 518 | | 参数名 | 参数说明 | 备注 | 519 | | -------- | -------- | -------- | 520 | | roleName | 角色名称 | 不能为空 | 521 | | roleDesc | 角色描述 | 可以为空 | 522 | 523 | - 响应参数 524 | 525 | | 参数名 | 参数说明 | 备注 | 526 | | -------- | -------- | ---- | 527 | | roleId | 角色 ID | | 528 | | roleName | 角色名称 | | 529 | | roleDesc | 角色描述 | | 530 | 531 | - 响应数据 532 | 533 | ```json 534 | { 535 | "data": { 536 | "roleId": 40, 537 | "roleName": "admin2", 538 | "roleDesc": "admin2Desc" 539 | }, 540 | "meta": { 541 | "msg": "创建成功", 542 | "status": 201 543 | } 544 | } 545 | ``` 546 | 547 | ### 1.5.3. 根据 ID 查询角色 548 | 549 | - 请求路径:roles/:id 550 | - 请求方法:get 551 | - 请求参数 552 | 553 | | 参数名 | 参数说明 | 备注 | 554 | | ------ | -------- | --------------------- | 555 | | :id | 角色 ID | 不能为空`携带在url中` | 556 | 557 | - 响应参数 558 | 559 | | 参数名 | 参数说明 | 备注 | 560 | | -------- | -------- | ---- | 561 | | roleId | 角色 ID | | 562 | | roleName | 角色名称 | | 563 | | roleDesc | 角色描述 | | 564 | 565 | - 响应数据 566 | 567 | ```json 568 | { 569 | "data": { 570 | "roleId": 31, 571 | "roleName": "测试角色", 572 | "roleDesc": "测试负责人" 573 | }, 574 | "meta": { 575 | "msg": "获取成功", 576 | "status": 200 577 | } 578 | } 579 | ``` 580 | 581 | ### 1.5.4. 编辑提交角色 582 | 583 | - 请求路径:roles/:id 584 | - 请求方法:put 585 | - 请求参数 586 | 587 | | 参数名 | 参数说明 | 备注 | 588 | | -------- | -------- | --------------------- | 589 | | :id | 角色 ID | 不能为空`携带在url中` | 590 | | roleName | 角色名称 | 不能为空 | 591 | | roleDesc | 角色描述 | 可以为空 | 592 | 593 | - 响应数据 594 | 595 | ```json 596 | { 597 | "data": { 598 | "roleId": 31, 599 | "roleName": "测试角色", 600 | "roleDesc": "测试角色描述" 601 | }, 602 | "meta": { 603 | "msg": "获取成功", 604 | "status": 200 605 | } 606 | } 607 | ``` 608 | 609 | ### 1.5.5. 删除角色 610 | 611 | - 请求路径:roles/:id 612 | - 请求方法:delete 613 | - 请求参数 614 | 615 | | 参数名 | 参数说明 | 备注 | 616 | | ------ | -------- | --------------------- | 617 | | :id | 角色 ID | 不能为空`携带在url中` | 618 | 619 | - 响应数据 620 | 621 | ```json 622 | { 623 | "data": null, 624 | "meta": { 625 | "msg": "删除成功", 626 | "status": 200 627 | } 628 | } 629 | ``` 630 | 631 | ### 1.5.6. 角色授权 632 | 633 | - 请求路径:roles/:roleId/rights 634 | - 请求方法:post 635 | - 请求参数:通过 `请求体` 发送给后端 636 | 637 | | 参数名 | 参数说明 | 备注 | 638 | | ------- | ---------------------- | ------------------------------------------------------------ | 639 | | :roleId | 角色 ID | 不能为空`携带在url中` | 640 | | rids | 权限 ID 列表(字符串) | 以 `,` 分割的权限 ID 列表(获取所有被选中、叶子节点的key和半选中节点的key, 包括 1,2,3级节点) | 641 | 642 | - 响应数据 643 | 644 | ```json 645 | { 646 | "data": null, 647 | "meta": { 648 | "msg": "更新成功", 649 | "status": 200 650 | } 651 | } 652 | ``` 653 | 654 | ### 1.5.7. 删除角色指定权限 655 | 656 | - 请求路径:roles/:roleId/rights/:rightId 657 | 658 | - 请求方法:delete 659 | 660 | - 请求参数 661 | 662 | | 参数名 | 参数说明 | 备注 | 663 | | -------- | -------- | --------------------- | 664 | | :roleId | 角色 ID | 不能为空`携带在url中` | 665 | | :rightId | 权限 ID | 不能为空`携带在url中` | 666 | 667 | - 响应数据说明 668 | 669 | - 返回的data, 是当前角色下最新的权限数据 670 | 671 | - 响应数据 672 | 673 | ```json 674 | { 675 | "data": [ 676 | { 677 | "id": 101, 678 | "authName": "商品管理", 679 | "path": null, 680 | "children": [ 681 | { 682 | "id": 104, 683 | "authName": "商品列表", 684 | "path": null, 685 | "children": [ 686 | { 687 | "id": 105, 688 | "authName": "添加商品", 689 | "path": null 690 | }, 691 | { 692 | "id": 116, 693 | "authName": "修改", 694 | "path": null 695 | } 696 | ] 697 | } 698 | ] 699 | } 700 | ], 701 | "meta": { 702 | "msg": "取消权限成功", 703 | "status": 200 704 | } 705 | } 706 | ``` 707 | 708 | ## 1.6. 商品分类管理 709 | 710 | ### 1.6.1. 商品分类数据列表 711 | 712 | - 请求路径:categories 713 | - 请求方法:get 714 | - 请求参数 715 | 716 | | 参数名 | 参数说明 | 备注 | 717 | | -------- | ------------------ | ------------------------------------------------------------ | 718 | | type | [1,2,3] | 值:1,2,3 分别表示显示一层二层三层分类列表
【可选参数】如果不传递,则默认获取所有级别的分类 | 719 | | pagenum | 当前页码值 | 【可选参数】如果不传递,则默认获取所有分类 | 720 | | pagesize | 每页显示多少条数据 | 【可选参数】如果不传递,则默认获取所有分类 | 721 | 722 | - 响应参数 723 | 724 | | 参数名 | 参数说明 | 备注 | 725 | | --------- | ------------ | ---- | 726 | | cat_id | 分类 ID | | 727 | | cat_name | 分类名称 | | 728 | | cat_pid | 分类父 ID | | 729 | | cat_level | 分类当前层级 | | 730 | 731 | - 响应数据 732 | 733 | ```json 734 | { 735 | "data": [ 736 | { 737 | "cat_id": 1, 738 | "cat_name": "大家电", 739 | "cat_pid": 0, 740 | "cat_level": 0, 741 | "cat_deleted": false, 742 | "children": [ 743 | { 744 | "cat_id": 3, 745 | "cat_name": "电视", 746 | "cat_pid": 1, 747 | "cat_level": 1, 748 | "cat_deleted": false, 749 | "children": [ 750 | { 751 | "cat_id": 6, 752 | "cat_name": "曲面电视", 753 | "cat_pid": 3, 754 | "cat_level": 2, 755 | "cat_deleted": false 756 | }, 757 | { 758 | "cat_id": 7, 759 | "cat_name": "海信", 760 | "cat_pid": 3, 761 | "cat_level": 2, 762 | "cat_deleted": false 763 | } 764 | ] 765 | } 766 | ] 767 | } 768 | ], 769 | "meta": { 770 | "msg": "获取成功", 771 | "status": 200 772 | } 773 | } 774 | ``` 775 | 776 | ### 1.6.2. 添加分类 777 | 778 | - 请求路径:categories 779 | - 请求方法:post 780 | - 请求参数 781 | 782 | | 参数名 | 参数说明 | 备注 | 783 | | --------- | --------- | ----------------------------------------------------------- | 784 | | cat_pid | 分类父 ID | 不能为空,如果要添加1级分类,则父分类Id应该设置为 `0` | 785 | | cat_name | 分类名称 | 不能为空 | 786 | | cat_level | 分类层级 | 不能为空,`0`表示一级分类;`1`表示二级分类;`2`表示三级分类 | 787 | 788 | - 响应数据 789 | 790 | ```json 791 | { 792 | "data": { 793 | "cat_id": 62, 794 | "cat_name": "相框", 795 | "cat_pid": "1", 796 | "cat_level": "1" 797 | }, 798 | "meta": { 799 | "msg": "创建成功", 800 | "status": 201 801 | } 802 | } 803 | ``` 804 | 805 | ### 1.6.3. 根据 id 查询分类 806 | 807 | - 请求路径:categories/:id 808 | - 请求方法:get 809 | - 请求参数 810 | 811 | | 参数名 | 参数说明 | 备注 | 812 | | ------ | -------- | --------------------- | 813 | | :id | 分类 ID | 不能为空`携带在url中` | 814 | 815 | - 响应数据 816 | 817 | ``` 818 | { 819 | "data": { 820 | "cat_id": 3, 821 | "cat_name": "厨卫电器", 822 | "cat_pid": 0, 823 | "cat_level": 0 824 | }, 825 | "meta": { 826 | "msg": "获取成功", 827 | "status": 200 828 | } 829 | } 830 | ``` 831 | 832 | ### 1.6.4. 编辑提交分类 833 | 834 | - 请求路径:categories/:id 835 | - 请求方法:put 836 | - 请求参数 837 | 838 | | 参数名 | 参数说明 | 备注 | 839 | | -------- | -------- | -------------------------------- | 840 | | :id | 分类 ID | 不能为空`携带在url中` | 841 | | cat_name | 分类名称 | 不能为空【此参数,放到请求体中】 | 842 | 843 | - 响应数据 844 | 845 | ``` 846 | { 847 | "data": { 848 | "cat_id": 22, 849 | "cat_name": "自拍杆", 850 | "cat_pid": 7, 851 | "cat_level": 2 852 | }, 853 | "meta": { 854 | "msg": "更新成功", 855 | "status": 200 856 | } 857 | } 858 | ``` 859 | 860 | ### 1.6.5. 删除分类 861 | 862 | - 请求路径:categories/:id 863 | - 请求方法:delete 864 | - 请求参数 865 | 866 | | 参数名 | 参数说明 | 备注 | 867 | | ------ | -------- | --------------------- | 868 | | :id | 分类 ID | 不能为空`携带在url中` | 869 | 870 | - 响应数据 871 | 872 | ``` 873 | { 874 | "data": null, 875 | "meta": { 876 | "msg": "删除成功", 877 | "status": 200 878 | } 879 | } 880 | ``` 881 | 882 | ## 1.7. 分类参数管理 883 | 884 | ### 1.7.1. 参数列表 885 | 886 | - 请求路径:categories/:id/attributes 887 | - 请求方法:get 888 | - 请求参数 889 | 890 | | 参数名 | 参数说明 | 备注 | 891 | | ------ | ----------- | --------------------------------------------------------- | 892 | | :id | 分类 ID | 不能为空`携带在url中` | 893 | | sel | [only,many] | 不能为空,通过 only 或 many 来获取分类静态参数还是动态参数 | 894 | 895 | - 响应参数 896 | 897 | | 参数名 | 参数说明 | 备注 | 898 | | ---------- | ---------------------------------------------- | ---- | 899 | | attr_id | 分类参数 ID | | 900 | | attr_name | 分类参数名称 | | 901 | | cat_id | 分类参数所属分类 | | 902 | | attr_sel | only:输入框(唯一) many:后台下拉列表/前台单选框 | | 903 | | attr_write | manual:手工录入 list:从列表选择 | | 904 | | attr_vals | 如果 attr_write:list,那么有值,该值以逗号分隔 | | 905 | 906 | - 响应数据 907 | 908 | ``` 909 | { 910 | "data": [ 911 | { 912 | "attr_id": 1, 913 | "attr_name": "cpu", 914 | "cat_id": 22, 915 | "attr_sel": "only", 916 | "attr_write": "manual", 917 | "attr_vals": "ffff" 918 | } 919 | ], 920 | "meta": { 921 | "msg": "获取成功", 922 | "status": 200 923 | } 924 | } 925 | ``` 926 | 927 | ### 1.7.2. 添加动态参数或者静态属性 928 | 929 | - 请求路径:categories/:id/attributes 930 | - 请求方法:post 931 | - 请求参数 932 | 933 | | 参数名 | 参数说明 | 备注 | 934 | | --------- | ------------------------------------------ | --------------------- | 935 | | :id | 分类 ID | 不能为空`携带在url中` | 936 | | attr_name | 参数名称 | 不能为空 | 937 | | attr_sel | [only,many] | 不能为空 | 938 | | attr_vals | 如果是 many 就需要填写值的选项,以逗号分隔 | 【可选参数】 | 939 | 940 | - 响应数据 941 | 942 | ``` 943 | { 944 | "data": { 945 | "attr_id": 44, 946 | "attr_name": "测试参数", 947 | "cat_id": "1", 948 | "attr_sel": "many", 949 | "attr_write": "list", 950 | "attr_vals": "a,b,c" 951 | }, 952 | "meta": { 953 | "msg": "创建成功", 954 | "status": 201 955 | } 956 | } 957 | ``` 958 | 959 | ### 1.7.3. 删除参数 960 | 961 | - 请求路径: categories/:id/attributes/:attrid 962 | - 请求方法:delete 963 | - 请求参数 964 | 965 | | 参数名 | 参数说明 | 备注 | 966 | | ------- | -------- | --------------------- | 967 | | :id | 分类 ID | 不能为空`携带在url中` | 968 | | :attrid | 参数 ID | 不能为空`携带在url中` | 969 | 970 | - 响应数据 971 | 972 | ``` 973 | { 974 | "data": null, 975 | "meta": { 976 | "msg": "删除成功", 977 | "status": 200 978 | } 979 | } 980 | ``` 981 | 982 | ### 1.7.4. 根据 ID 查询参数 983 | 984 | - 请求路径:categories/:id/attributes/:attrId 985 | - 请求方法:get 986 | - 请求参数 987 | 988 | | 参数名 | 参数说明 | 备注 | 989 | | --------- | ------------------------------------------ | --------------------- | 990 | | :id | 分类 ID | 不能为空`携带在url中` | 991 | | :attrId | 属性 ID | 不能为空`携带在url中` | 992 | | attr_sel | [only,many] | 不能为空 | 993 | | attr_vals | 如果是 many 就需要填写值的选项,以逗号分隔 | | 994 | 995 | - 响应数据 996 | 997 | ``` 998 | { 999 | "data": { 1000 | "attr_id": 1, 1001 | "attr_name": "cpu", 1002 | "cat_id": 22, 1003 | "attr_sel": "only", 1004 | "attr_write": "manual", 1005 | "attr_vals": "ffff" 1006 | }, 1007 | "meta": { 1008 | "msg": "获取成功", 1009 | "status": 200 1010 | } 1011 | } 1012 | ``` 1013 | 1014 | ### 1.7.5. 编辑提交参数 1015 | 1016 | - 请求路径:categories/:id/attributes/:attrId 1017 | - 请求方法:put 1018 | - 请求参数 1019 | 1020 | | 参数名 | 参数说明 | 备注 | 1021 | | --------- | ---------------------- | -------------------------- | 1022 | | :id | 分类 ID | 不能为空`携带在url中` | 1023 | | :attrId | 属性 ID | 不能为空`携带在url中` | 1024 | | attr_name | 新属性的名字 | 不能为空,携带在`请求体`中 | 1025 | | attr_sel | 属性的类型[many或only] | 不能为空,携带在`请求体`中 | 1026 | | attr_vals | 参数的属性值 | 可选参数,携带在`请求体`中 | 1027 | 1028 | - 响应数据 1029 | 1030 | ``` 1031 | { 1032 | "data": { 1033 | "attr_id": 9, 1034 | "attr_name": "测试更新", 1035 | "cat_id": "43", 1036 | "attr_sel": "only", 1037 | "attr_write": "manual", 1038 | "attr_vals": "abc" 1039 | }, 1040 | "meta": { 1041 | "msg": "更新成功", 1042 | "status": 200 1043 | } 1044 | } 1045 | ``` 1046 | 1047 | ## 1.8. 商品管理 1048 | 1049 | ### 1.8.1. 商品列表数据 1050 | 1051 | - 请求路径:goods 1052 | - 请求方法:get 1053 | - 请求参数 1054 | 1055 | | 参数名 | 参数说明 | 备注 | 1056 | | -------- | ------------ | -------- | 1057 | | query | 查询参数 | 可以为空 | 1058 | | pagenum | 当前页码 | 不能为空 | 1059 | | pagesize | 每页显示条数 | 不能为空 | 1060 | 1061 | - 响应参数 1062 | 1063 | | 参数名 | 参数说明 | 备注 | 1064 | | ------------ | ------------ | -------------------------------------- | 1065 | | total | 总共商品条数 | | 1066 | | pagenum | 当前商品页数 | | 1067 | | goods_id | 商品 ID | | 1068 | | goods_name | 商品名称 | | 1069 | | goods_price | 价格 | | 1070 | | goods_number | 数量 | | 1071 | | goods_weight | 重量 | 不能为空 | 1072 | | goods_state | 商品状态 | 商品状态 0: 未通过 1: 审核中 2: 已审核 | 1073 | | add_time | 添加时间 | | 1074 | | upd_time | 更新时间 | | 1075 | | hot_mumber | 热销品数量 | | 1076 | | is_promote | 是否是热销品 | | 1077 | 1078 | - 响应数据 1079 | 1080 | ``` 1081 | { 1082 | "data": { 1083 | "total": 50, 1084 | "pagenum": "1", 1085 | "goods": [ 1086 | { 1087 | "goods_id": 144, 1088 | "goods_name": "asfdsd", 1089 | "goods_price": 1, 1090 | "goods_number": 1, 1091 | "goods_weight": 1, 1092 | "goods_state": null, 1093 | "add_time": 1512954923, 1094 | "upd_time": 1512954923, 1095 | "hot_mumber": 0, 1096 | "is_promote": false 1097 | } 1098 | ] 1099 | }, 1100 | "meta": { 1101 | "msg": "获取成功", 1102 | "status": 200 1103 | } 1104 | } 1105 | ``` 1106 | 1107 | ### 1.8.2. 添加商品 1108 | 1109 | - 请求路径:goods 1110 | - 请求方法:post 1111 | - 请求参数 1112 | 1113 | | 参数名 | 参数说明 | 备注 | 1114 | | --------------- | ------------------------------------------------- | -------- | 1115 | | goods_name | 商品名称 | 不能为空 | 1116 | | goods_cat | 以为','分割的分类列表 | 不能为空 | 1117 | | goods_price | 价格 | 不能为空 | 1118 | | goods_number | 数量 | 不能为空 | 1119 | | goods_weight | 重量 | 不能为空 | 1120 | | goods_introduce | 介绍 | 可以为空 | 1121 | | pics | 上传的图片临时路径(对象) | 可以为空 | 1122 | | attrs | 商品的参数(数组),包含 `动态参数` 和 `静态属性` | 可以为空 | 1123 | 1124 | - 请求数据 1125 | 1126 | ```json 1127 | { 1128 | "goods_name":"test_goods_name2", 1129 | "goods_cat": "1,2,3", 1130 | "goods_price":20, 1131 | "goods_number":30, 1132 | "goods_weight":40, 1133 | "goods_introduce":"abc", 1134 | "pics":[ 1135 | {"pic":"/tmp_uploads/30f08d52c551ecb447277eae232304b8"} 1136 | ], 1137 | "attrs":[ 1138 | { 1139 | "attr_id":15, 1140 | "attr_value":"ddd" 1141 | }, 1142 | { 1143 | "attr_id":15, 1144 | "attr_value":"eee" 1145 | } 1146 | ] 1147 | } 1148 | ``` 1149 | 1150 | - 响应参数 1151 | 1152 | | 参数名 | 参数说明 | 备注 | 1153 | | ------------ | -------------------------- | ------------------------------------------------------------ | 1154 | | total | 总共商品条数 | | 1155 | | pagenum | 当前商品页数 | | 1156 | | goods_id | 商品 ID | | 1157 | | goods_cat | 以为','分割的分类列表 | | 1158 | | goods_name | 商品名称 | | 1159 | | goods_price | 价格 | | 1160 | | goods_number | 数量 | | 1161 | | goods_weight | 重量 | 不能为空 | 1162 | | goods_state | 商品状态 | 商品状态 0: 未通过 1: 审核中 2: 已审核 | 1163 | | add_time | 添加时间 | | 1164 | | upd_time | 更新时间 | | 1165 | | hot_mumber | 热销品数量 | | 1166 | | is_promote | 是否是热销品 | | 1167 | | pics | 上传的图片临时路径(对象) | pics_id:图片 ID,goods_id:商品 ID,pics_big:大图,pics_mid:中图,pics_sma:小图 | 1168 | | attrs | 商品的参数(数组) | goods_id:商品 ID,attr_value:当前商品的参数值,add_price:浮动价格,attr_vals:预定义的参数值,attr_sel:手动输入,还是单选, | 1169 | 1170 | - 响应数据 1171 | 1172 | ```json 1173 | { 1174 | "data": { 1175 | "goods_id": 145, 1176 | "goods_name": "test_goods_name2", 1177 | "goods_price": 20, 1178 | "cat_id": 1, 1179 | "goods_number": 30, 1180 | "goods_weight": 40, 1181 | "goods_introduce": "abc", 1182 | "goods_big_logo": "", 1183 | "goods_small_logo": "", 1184 | "goods_state": 1, 1185 | "add_time": 1512962370, 1186 | "upd_time": 1512962370, 1187 | "hot_mumber": 0, 1188 | "is_promote": false, 1189 | "pics": [ 1190 | { 1191 | "pics_id": 397, 1192 | "goods_id": 145, 1193 | "pics_big": "uploads/goodspics/big_30f08d52c551ecb447277eae232304b8", 1194 | "pics_mid": "uploads/goodspics/mid_30f08d52c551ecb447277eae232304b8", 1195 | "pics_sma": "uploads/goodspics/sma_30f08d52c551ecb447277eae232304b8" 1196 | } 1197 | ], 1198 | "attrs": [ 1199 | { 1200 | "goods_id": 145, 1201 | "attr_id": 15, 1202 | "attr_value": "ddd", 1203 | "add_price": null, 1204 | "attr_name": "fffffff", 1205 | "attr_sel": "many", 1206 | "attr_write": "list", 1207 | "attr_vals": "" 1208 | }, 1209 | { 1210 | "goods_id": 145, 1211 | "attr_id": 15, 1212 | "attr_value": "eee", 1213 | "add_price": null, 1214 | "attr_name": "fffffff", 1215 | "attr_sel": "many", 1216 | "attr_write": "list", 1217 | "attr_vals": "" 1218 | } 1219 | ] 1220 | }, 1221 | "meta": { 1222 | "msg": "创建商品成功", 1223 | "status": 201 1224 | } 1225 | } 1226 | ``` 1227 | 1228 | ### 1.8.3. 根据 ID 查询商品 1229 | 1230 | - 请求路径:goods/:id 1231 | - 请求方法:get 1232 | - 请求参数 1233 | 1234 | | 参数名 | 参数说明 | 备注 | 1235 | | ------ | -------- | --------------------- | 1236 | | id | 商品 ID | 不能为空`携带在url中` | 1237 | 1238 | - 响应参数 1239 | 1240 | | 参数名 | 参数说明 | 备注 | 1241 | | ------------ | -------------------------- | ------------------------------------------------------------ | 1242 | | total | 总共商品条数 | | 1243 | | pagenum | 当前商品页数 | | 1244 | | goods_id | 商品 ID | | 1245 | | goods_name | 商品名称 | | 1246 | | goods_price | 价格 | | 1247 | | goods_number | 数量 | | 1248 | | goods_weight | 重量 | 不能为空 | 1249 | | goods_state | 商品状态 | 商品状态 0: 未通过 1: 审核中 2: 已审核 | 1250 | | add_time | 添加时间 | | 1251 | | upd_time | 更新时间 | | 1252 | | hot_mumber | 热销品数量 | | 1253 | | is_promote | 是否是热销品 | | 1254 | | pics | 上传的图片临时路径(对象) | pics_id:图片 ID,goods_id:商品 ID,pics_big:大图,pics_mid:中图,pics_sma:小图 | 1255 | | attrs | 商品的参数(数组) | goods_id:商品 ID,attr_value:当前商品的参数值,add_price:浮动价格,attr_vals:预定义的参数值,attr_sel:手动输入,还是单选, | 1256 | 1257 | - 响应数据 1258 | 1259 | ``` 1260 | { 1261 | "data": { 1262 | "goods_id": 145, 1263 | "goods_name": "test_goods_name2", 1264 | "goods_price": 20, 1265 | "goods_number": 30, 1266 | "goods_weight": 40, 1267 | "goods_introduce": "abc", 1268 | "goods_big_logo": "", 1269 | "goods_small_logo": "", 1270 | "goods_state": 1, 1271 | "add_time": 1512962370, 1272 | "upd_time": 1512962370, 1273 | "hot_mumber": 0, 1274 | "is_promote": false, 1275 | "pics": [ 1276 | { 1277 | "pics_id": 397, 1278 | "goods_id": 145, 1279 | "pics_big": "uploads/goodspics/big_30f08d52c551ecb447277eae232304b8", 1280 | "pics_mid": "uploads/goodspics/mid_30f08d52c551ecb447277eae232304b8", 1281 | "pics_sma": "uploads/goodspics/sma_30f08d52c551ecb447277eae232304b8" 1282 | } 1283 | ], 1284 | "attrs": [ 1285 | { 1286 | "goods_id": 145, 1287 | "attr_id": 15, 1288 | "attr_value": "ddd", 1289 | "add_price": null, 1290 | "attr_name": "fffffff", 1291 | "attr_sel": "many", 1292 | "attr_write": "list", 1293 | "attr_vals": "" 1294 | }, 1295 | { 1296 | "goods_id": 145, 1297 | "attr_id": 15, 1298 | "attr_value": "eee", 1299 | "add_price": null, 1300 | "attr_name": "fffffff", 1301 | "attr_sel": "many", 1302 | "attr_write": "list", 1303 | "attr_vals": "" 1304 | } 1305 | ] 1306 | }, 1307 | "meta": { 1308 | "msg": "创建商品成功", 1309 | "status": 201 1310 | } 1311 | } 1312 | ``` 1313 | 1314 | ### 1.8.4. 编辑提交商品 1315 | 1316 | - 请求路径:goods/:id 1317 | - 请求方法:put 1318 | - 请求参数 1319 | 1320 | | 参数名 | 参数说明 | 备注 | 1321 | | --------------- | -------------------------- | --------------------- | 1322 | | id | 商品 ID | 不能为空`携带在url中` | 1323 | | goods_name | 商品名称 | 不能为空 | 1324 | | goods_price | 价格 | 不能为空 | 1325 | | goods_number | 数量 | 不能为空 | 1326 | | goods_weight | 重量 | 不能为空 | 1327 | | goods_introduce | 介绍 | 可以为空 | 1328 | | pics | 上传的图片临时路径(对象) | 可以为空 | 1329 | | attrs | 商品的参数(数组) | 可以为空 | 1330 | 1331 | - 请求数据 1332 | 1333 | ``` 1334 | { 1335 | "goods_name":"test_goods_name2", 1336 | "goods_price":20, 1337 | "goods_number":30, 1338 | "goods_weight":40, 1339 | "goods_introduce":"abc", 1340 | "pics":[ 1341 | {"pic":"/tmp_uploads/30f08d52c551ecb447277eae232304b8"} 1342 | ], 1343 | "attrs":[ 1344 | { 1345 | "attr_id":15, 1346 | "attr_value":"ddd" 1347 | }, 1348 | { 1349 | "attr_id":15, 1350 | "attr_value":"eee" 1351 | } 1352 | ] 1353 | } 1354 | ``` 1355 | 1356 | - 响应参数 1357 | 1358 | | 参数名 | 参数说明 | 备注 | 1359 | | ------------ | -------------------------- | ------------------------------------------------------------ | 1360 | | total | 总共商品条数 | | 1361 | | pagenum | 当前商品页数 | | 1362 | | goods_id | 商品 ID | | 1363 | | goods_name | 商品名称 | | 1364 | | goods_price | 价格 | | 1365 | | goods_number | 数量 | | 1366 | | goods_weight | 重量 | 不能为空 | 1367 | | goods_state | 商品状态 | 商品状态 0: 未通过 1: 审核中 2: 已审核 | 1368 | | add_time | 添加时间 | | 1369 | | upd_time | 更新时间 | | 1370 | | hot_mumber | 热销品数量 | | 1371 | | is_promote | 是否是热销品 | | 1372 | | pics | 上传的图片临时路径(对象) | pics_id:图片 ID,goods_id:商品 ID,pics_big:大图,pics_mid:中图,pics_sma:小图 | 1373 | | attrs | 商品的参数(数组) | goods_id:商品 ID,attr_value:当前商品的参数值,add_price:浮动价格,attr_vals:预定义的参数值,attr_sel:手动输入,还是单选, | 1374 | 1375 | - 响应数据 1376 | 1377 | ``` 1378 | { 1379 | "data": { 1380 | "goods_id": 145, 1381 | "goods_name": "test_goods_name2", 1382 | "goods_price": 20, 1383 | "goods_number": 30, 1384 | "goods_weight": 40, 1385 | "goods_introduce": "abc", 1386 | "goods_big_logo": "", 1387 | "goods_small_logo": "", 1388 | "goods_state": 1, 1389 | "add_time": 1512962370, 1390 | "upd_time": 1512962370, 1391 | "hot_mumber": 0, 1392 | "is_promote": false, 1393 | "pics": [ 1394 | { 1395 | "pics_id": 397, 1396 | "goods_id": 145, 1397 | "pics_big": "uploads/goodspics/big_30f08d52c551ecb447277eae232304b8", 1398 | "pics_mid": "uploads/goodspics/mid_30f08d52c551ecb447277eae232304b8", 1399 | "pics_sma": "uploads/goodspics/sma_30f08d52c551ecb447277eae232304b8" 1400 | } 1401 | ], 1402 | "attrs": [ 1403 | { 1404 | "goods_id": 145, 1405 | "attr_id": 15, 1406 | "attr_value": "ddd", 1407 | "add_price": null, 1408 | "attr_name": "fffffff", 1409 | "attr_sel": "many", 1410 | "attr_write": "list", 1411 | "attr_vals": "" 1412 | }, 1413 | { 1414 | "goods_id": 145, 1415 | "attr_id": 15, 1416 | "attr_value": "eee", 1417 | "add_price": null, 1418 | "attr_name": "fffffff", 1419 | "attr_sel": "many", 1420 | "attr_write": "list", 1421 | "attr_vals": "" 1422 | } 1423 | ] 1424 | }, 1425 | "meta": { 1426 | "msg": "创建商品成功", 1427 | "status": 201 1428 | } 1429 | } 1430 | ``` 1431 | 1432 | ### 1.8.5. 删除商品 1433 | 1434 | - 请求路径:goods/:id 1435 | - 请求方法:delete 1436 | - 请求参数 1437 | 1438 | | 参数名 | 参数说明 | 备注 | 1439 | | ------ | -------- | --------------------- | 1440 | | id | 商品 ID | 不能为空`携带在url中` | 1441 | 1442 | - 响应数据 1443 | 1444 | ``` 1445 | { 1446 | "data": null, 1447 | "meta": { 1448 | "msg": "删除成功", 1449 | "status": 200 1450 | } 1451 | } 1452 | ``` 1453 | 1454 | \###同步商品图片 1455 | 1456 | - 请求路径:goods/:id/pics 1457 | - 请求方法:put 1458 | - 请求参数 1459 | 1460 | | 参数名 | 参数说明 | 备注 | 1461 | | ------ | ------------ | ------------------------------------------------------------ | 1462 | | id | 商品 ID | 不能为空`携带在url中` | 1463 | | pics | 商品图片集合 | 如果有 pics_id 字段会保留该图片,如果没有 pics_id 但是有 pic 字段就会新生成图片数据 | 1464 | 1465 | - 请求数据 1466 | 1467 | ``` 1468 | ;[ 1469 | { pic: 'tmp_uploads/db28f6316835836e97653b5c75e418be.png' }, 1470 | { 1471 | pics_id: 397, 1472 | goods_id: 145, 1473 | pics_big: 'uploads/goodspics/big_30f08d52c551ecb447277eae232304b8', 1474 | pics_mid: 'uploads/goodspics/mid_30f08d52c551ecb447277eae232304b8', 1475 | pics_sma: 'uploads/goodspics/sma_30f08d52c551ecb447277eae232304b8' 1476 | } 1477 | ] 1478 | ``` 1479 | 1480 | - 响应数据 1481 | 1482 | ``` 1483 | { 1484 | "data": { 1485 | "goods_id": 96, 1486 | "goods_name": "iphoneXX", 1487 | "goods_price": 2, 1488 | "goods_number": 22, 1489 | "goods_weight": 22, 1490 | "goods_introduce": null, 1491 | "goods_big_logo": "./uploads/goods/20171113/483a3b8e99e534ec3e4312dbbaee7c9d.jpg", 1492 | "goods_small_logo": "./uploads/goods/20171113/small_483a3b8e99e534ec3e4312dbbaee7c9d.jpg", 1493 | "goods_state": 0, 1494 | "is_del": "1", 1495 | "add_time": 1510045904, 1496 | "upd_time": 1512635159, 1497 | "delete_time": 1512635159, 1498 | "hot_mumber": 0, 1499 | "is_promote": false, 1500 | "pics": [ 1501 | { 1502 | "pics_id": 383, 1503 | "goods_id": 96, 1504 | "pics_big": "uploads/goodspics/big_6f5750132abd3f5b2b93dd722fcde653.jpg", 1505 | "pics_mid": "uploads/goodspics/mid_6f5750132abd3f5b2b93dd722fcde653.jpg", 1506 | "pics_sma": "uploads/goodspics/sma_6f5750132abd3f5b2b93dd722fcde653.jpg" 1507 | } 1508 | ], 1509 | "attrs": [ 1510 | { 1511 | "goods_id": 96, 1512 | "attr_id": 15, 1513 | "attr_value": "eee", 1514 | "add_price": null, 1515 | "attr_name": "fffffff", 1516 | "attr_sel": "many", 1517 | "attr_write": "list", 1518 | "attr_vals": "" 1519 | }, 1520 | { 1521 | "goods_id": 96, 1522 | "attr_id": 15, 1523 | "attr_value": "ddd", 1524 | "add_price": null, 1525 | "attr_name": "fffffff", 1526 | "attr_sel": "many", 1527 | "attr_write": "list", 1528 | "attr_vals": "" 1529 | } 1530 | ] 1531 | }, 1532 | "meta": { 1533 | "msg": "更新成功", 1534 | "status": 200 1535 | } 1536 | } 1537 | ``` 1538 | 1539 | \###同步商品属性 1540 | 1541 | - 请求路径:goods/:id/attributes 1542 | - 请求方法:put 1543 | - 请求参数 1544 | 1545 | | 参数名 | 参数说明 | 备注 | 1546 | | ------ | -------- | --------------------- | 1547 | | id | 商品 ID | 不能为空`携带在url中` | 1548 | 1549 | - 请求数据 1550 | 1551 | ``` 1552 | ;[ 1553 | { 1554 | attr_id: 15, 1555 | attr_value: 'ddd' 1556 | }, 1557 | { 1558 | attr_id: 15, 1559 | attr_value: 'eee' 1560 | } 1561 | ] 1562 | ``` 1563 | 1564 | - 响应数据 1565 | 1566 | ``` 1567 | { 1568 | "data": { 1569 | "goods_id": 96, 1570 | "goods_name": "iphoneXX", 1571 | "goods_price": 2, 1572 | "goods_number": 22, 1573 | "goods_weight": 22, 1574 | "goods_introduce": null, 1575 | "goods_big_logo": "./uploads/goods/20171113/483a3b8e99e534ec3e4312dbbaee7c9d.jpg", 1576 | "goods_small_logo": "./uploads/goods/20171113/small_483a3b8e99e534ec3e4312dbbaee7c9d.jpg", 1577 | "goods_state": 0, 1578 | "is_del": "1", 1579 | "add_time": 1510045904, 1580 | "upd_time": 1512635159, 1581 | "delete_time": 1512635159, 1582 | "hot_mumber": 0, 1583 | "is_promote": false, 1584 | "pics": [ 1585 | { 1586 | "pics_id": 383, 1587 | "goods_id": 96, 1588 | "pics_big": "uploads/goodspics/big_6f5750132abd3f5b2b93dd722fcde653.jpg", 1589 | "pics_mid": "uploads/goodspics/mid_6f5750132abd3f5b2b93dd722fcde653.jpg", 1590 | "pics_sma": "uploads/goodspics/sma_6f5750132abd3f5b2b93dd722fcde653.jpg" 1591 | } 1592 | ], 1593 | "attrs": [ 1594 | { 1595 | "goods_id": 96, 1596 | "attr_id": 15, 1597 | "attr_value": "eee", 1598 | "add_price": null, 1599 | "attr_name": "fffffff", 1600 | "attr_sel": "many", 1601 | "attr_write": "list", 1602 | "attr_vals": "" 1603 | }, 1604 | { 1605 | "goods_id": 96, 1606 | "attr_id": 15, 1607 | "attr_value": "ddd", 1608 | "add_price": null, 1609 | "attr_name": "fffffff", 1610 | "attr_sel": "many", 1611 | "attr_write": "list", 1612 | "attr_vals": "" 1613 | } 1614 | ] 1615 | }, 1616 | "meta": { 1617 | "msg": "更新成功", 1618 | "status": 200 1619 | } 1620 | } 1621 | ``` 1622 | 1623 | \###商品图片处理必须安装 GraphicsMagick 1624 | 1625 | - linux 1626 | 1627 | ``` 1628 | apt-get install GraphicsMagick 1629 | ``` 1630 | 1631 | - Mac OS X 1632 | 1633 | ``` 1634 | brew install GraphicsMagick 1635 | ``` 1636 | 1637 | - Windows [点击下载](https://sourceforge.net/projects/graphicsmagick/files/graphicsmagick-binaries/1.3.27/GraphicsMagick-1.3.27-Q8-win64-dll.exe/download) 1638 | 1639 | ## 1.9. 图片上传 1640 | 1641 | - 请求路径:upload 1642 | - 请求方法:post 1643 | - 请求参数 1644 | 1645 | | 参数名 | 参数说明 | 备注 | 1646 | | ------ | -------- | ---- | 1647 | | file | 上传文件 | | 1648 | 1649 | - 响应数据 1650 | 1651 | ``` 1652 | { 1653 | "data": { 1654 | "tmp_path": "tmp_uploads/ccfc5179a914e94506bcbb7377e8985f.png", 1655 | "url": "http://127.0.0.1:8888tmp_uploads/ccfc5179a914e94506bcbb7377e8985f.png" 1656 | }, 1657 | "meta": { 1658 | "msg": "上传成功", 1659 | "status": 200 1660 | } 1661 | } 1662 | ``` 1663 | 1664 | ## 1.10. 订单管理 1665 | 1666 | ### 1.10.1. 订单数据列表 1667 | 1668 | - 请求路径:orders 1669 | - 请求方法:get 1670 | - 请求参数 1671 | 1672 | | 参数名 | 参数说明 | 备注 | 1673 | | -------------------- | --------------- | -------- | 1674 | | query | 查询参数 | 可以为空 | 1675 | | pagenum | 当前页码 | 不能为空 | 1676 | | pagesize | 每页显示条数 | 不能为空 | 1677 | | user_id | 用户 ID | 可以为空 | 1678 | | pay_status | 支付状态 | 可以为空 | 1679 | | is_send | 是否发货 | 可以为空 | 1680 | | order_fapiao_title | ['个人','公司'] | 可以为空 | 1681 | | order_fapiao_company | 公司名称 | 可以为空 | 1682 | | order_fapiao_content | 发票内容 | 可以为空 | 1683 | | consignee_addr | 发货地址 | 可以为空 | 1684 | 1685 | - 响应数据 1686 | 1687 | ``` 1688 | { 1689 | "data": { 1690 | "total": 1, 1691 | "pagenum": "1", 1692 | "goods": [ 1693 | { 1694 | "order_id": 47, 1695 | "user_id": 133, 1696 | "order_number": "itcast-59e7502d7993d", 1697 | "order_price": 322, 1698 | "order_pay": "1", 1699 | "is_send": "是", 1700 | "trade_no": "", 1701 | "order_fapiao_title": "个人", 1702 | "order_fapiao_company": "", 1703 | "order_fapiao_content": "办公用品", 1704 | "consignee_addr": "a:7:{s:6:\"cgn_id\";i:1;s:7:\"user_id\";i:133;s:8:\"cgn_name\";s:9:\"王二柱\";s:11:\"cgn_address\";s:51:\"北京市海淀区苏州街长远天地大厦305室\";s:7:\"cgn_tel\";s:11:\"13566771298\";s:8:\"cgn_code\";s:6:\"306810\";s:11:\"delete_time\";N;}", 1705 | "pay_status": "1", 1706 | "create_time": 1508331565, 1707 | "update_time": 1508331565 1708 | } 1709 | ] 1710 | }, 1711 | "meta": { 1712 | "msg": "获取成功", 1713 | "status": 200 1714 | } 1715 | } 1716 | ``` 1717 | 1718 | ### 1.10.2. 修改订单状态 1719 | 1720 | - 请求路径:orders/:id 1721 | - 请求方法:put 1722 | - 请求参数 1723 | 1724 | | 参数名 | 参数说明 | 备注 | 1725 | | ------------ | ------------ | ------------------------------------------ | 1726 | | id | 订单 ID | 不能为空`携带在url中` | 1727 | | is_send | 订单是否发货 | 1:已经发货,0:未发货 | 1728 | | order_pay | 订单支付 | 支付方式 0 未支付 1 支付宝 2 微信 3 银行卡 | 1729 | | order_price | 订单价格 | | 1730 | | order_number | 订单数量 | | 1731 | | pay_status | 支付状态 | 订单状态: 0 未付款、1 已付款 | 1732 | 1733 | - 请求数据说明 1734 | - 所有请求数据都是增量更新,如果参数不填写,就不会更新该字段 1735 | - 响应数据 1736 | 1737 | ``` 1738 | { 1739 | "data": { 1740 | "order_id": 67, 1741 | "user_id": 1, 1742 | "order_number": "itcast-g7kmck71vjaujfgoi", 1743 | "order_price": 20, 1744 | "order_pay": "0", 1745 | "is_send": "否", 1746 | "trade_no": "", 1747 | "order_fapiao_title": "个人", 1748 | "order_fapiao_company": "", 1749 | "order_fapiao_content": "", 1750 | "consignee_addr": "", 1751 | "pay_status": "0", 1752 | "create_time": 1512533560, 1753 | "update_time": 1512533560, 1754 | "goods": [ 1755 | { 1756 | "id": 82, 1757 | "order_id": 67, 1758 | "goods_id": 96, 1759 | "goods_price": 333, 1760 | "goods_number": 2, 1761 | "goods_total_price": 999 1762 | }, 1763 | { 1764 | "id": 83, 1765 | "order_id": 67, 1766 | "goods_id": 95, 1767 | "goods_price": 666, 1768 | "goods_number": 5, 1769 | "goods_total_price": 999 1770 | } 1771 | ] 1772 | }, 1773 | "meta": { 1774 | "msg": "获取成功", 1775 | "status": 200 1776 | } 1777 | } 1778 | ``` 1779 | 1780 | ### 1.10.3. 查看订单详情 1781 | 1782 | - 请求路径:orders/:id 1783 | - 请求方法:get 1784 | - 请求参数 1785 | 1786 | | 参数名 | 参数说明 | 备注 | 1787 | | ------ | -------- | --------------------- | 1788 | | id | 订单 ID | 不能为空`携带在url中` | 1789 | 1790 | - 响应数据 1791 | 1792 | ``` 1793 | { 1794 | "data": { 1795 | "order_id": 67, 1796 | "user_id": 1, 1797 | "order_number": "itcast-g7kmck71vjaujfgoi", 1798 | "order_price": 20, 1799 | "order_pay": "0", 1800 | "is_send": "否", 1801 | "trade_no": "", 1802 | "order_fapiao_title": "个人", 1803 | "order_fapiao_company": "", 1804 | "order_fapiao_content": "", 1805 | "consignee_addr": "", 1806 | "pay_status": "0", 1807 | "create_time": 1512533560, 1808 | "update_time": 1512533560, 1809 | "goods": [ 1810 | { 1811 | "id": 82, 1812 | "order_id": 67, 1813 | "goods_id": 96, 1814 | "goods_price": 333, 1815 | "goods_number": 2, 1816 | "goods_total_price": 999 1817 | }, 1818 | { 1819 | "id": 83, 1820 | "order_id": 67, 1821 | "goods_id": 95, 1822 | "goods_price": 666, 1823 | "goods_number": 5, 1824 | "goods_total_price": 999 1825 | } 1826 | ] 1827 | }, 1828 | "meta": { 1829 | "msg": "获取成功", 1830 | "status": 200 1831 | } 1832 | } 1833 | ``` 1834 | 1835 | 1836 | 1837 | ### 1.10.4. 修改地址 1838 | 1839 | 1. [省市区/县联动效果 - 结合ElementUI的 el-cascader 组件](https://github.com/iceyangcc/provinces-china) 1840 | 1841 | ### 1.10.5. 查看物流信息 1842 | 1843 | + 请求路径:/kuaidi/:id 1844 | 1845 | + 请求方法:get 1846 | 1847 | + 供测试的物流单号:1106975712662 1848 | 1849 | + 响应数据: 1850 | 1851 | ```json 1852 | { 1853 | "data": [ 1854 | { 1855 | "time": "2018-05-10 09:39:00", 1856 | "ftime": "2018-05-10 09:39:00", 1857 | "context": "已签收,感谢使用顺丰,期待再次为您服务", 1858 | "location": "" 1859 | }, 1860 | { 1861 | "time": "2018-05-10 08:23:00", 1862 | "ftime": "2018-05-10 08:23:00", 1863 | "context": "[北京市]北京海淀育新小区营业点派件员 顺丰速运 95338正在为您派件", 1864 | "location": "" 1865 | }, 1866 | { 1867 | "time": "2018-05-10 07:32:00", 1868 | "ftime": "2018-05-10 07:32:00", 1869 | "context": "快件到达 [北京海淀育新小区营业点]", 1870 | "location": "" 1871 | }, 1872 | { 1873 | "time": "2018-05-10 02:03:00", 1874 | "ftime": "2018-05-10 02:03:00", 1875 | "context": "快件在[北京顺义集散中心]已装车,准备发往 [北京海淀育新小区营业点]", 1876 | "location": "" 1877 | }, 1878 | { 1879 | "time": "2018-05-09 23:05:00", 1880 | "ftime": "2018-05-09 23:05:00", 1881 | "context": "快件到达 [北京顺义集散中心]", 1882 | "location": "" 1883 | }, 1884 | { 1885 | "time": "2018-05-09 21:21:00", 1886 | "ftime": "2018-05-09 21:21:00", 1887 | "context": "快件在[北京宝胜营业点]已装车,准备发往 [北京顺义集散中心]", 1888 | "location": "" 1889 | }, 1890 | { 1891 | "time": "2018-05-09 13:07:00", 1892 | "ftime": "2018-05-09 13:07:00", 1893 | "context": "顺丰速运 已收取快件", 1894 | "location": "" 1895 | }, 1896 | { 1897 | "time": "2018-05-09 12:25:03", 1898 | "ftime": "2018-05-09 12:25:03", 1899 | "context": "卖家发货", 1900 | "location": "" 1901 | }, 1902 | { 1903 | "time": "2018-05-09 12:22:24", 1904 | "ftime": "2018-05-09 12:22:24", 1905 | "context": "您的订单将由HLA(北京海淀区清河中街店)门店安排发货。", 1906 | "location": "" 1907 | }, 1908 | { 1909 | "time": "2018-05-08 21:36:04", 1910 | "ftime": "2018-05-08 21:36:04", 1911 | "context": "商品已经下单", 1912 | "location": "" 1913 | } 1914 | ], 1915 | "meta": { "status": 200, "message": "获取物流信息成功!" } 1916 | } 1917 | 1918 | ``` 1919 | 1920 | 1921 | ## 1.11. 数据统计 1922 | 1923 | ### 1.11.1. 基于时间统计的折线图 1924 | 1925 | - 请求路径:reports/type/1 1926 | 1927 | - 请求方法:get 1928 | 1929 | - 响应数据 1930 | 1931 | - 需要合并的选项 1932 | 1933 | ```js 1934 | options: { 1935 | title: { 1936 | text: '用户来源' 1937 | }, 1938 | tooltip: { 1939 | trigger: 'axis', 1940 | axisPointer: { 1941 | type: 'cross', 1942 | label: { 1943 | backgroundColor: '#E9EEF3' 1944 | } 1945 | } 1946 | }, 1947 | grid: { 1948 | left: '3%', 1949 | right: '4%', 1950 | bottom: '3%', 1951 | containLabel: true 1952 | }, 1953 | xAxis: [ 1954 | { 1955 | boundaryGap: false 1956 | } 1957 | ], 1958 | yAxis: [ 1959 | { 1960 | type: 'value' 1961 | } 1962 | ] 1963 | } 1964 | ``` --------------------------------------------------------------------------------