自定义验证规则
data() {
var validateTel = (rule, value, callback) => {
let reg = /^1[3,4,5,6,7,8,9][0-9]{9}$/;
if (!reg.test(value)) {
callback(new Error('请输入正确的手机号码'));
} else {
callback();
}
};
var validateConfirmPassword = (rule, value, callback) => {
if (value !== this.tenant.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
tenantRules:{
companyName:[
{ required: true, message: '公司名称不能为空', trigger: 'blur' }
],
companyNum:[
{ required: true, message: '公司电话不能为空', trigger: 'blur' },
{ validator: validateTel, trigger: 'blur' }
],
username:[
{ required: true, message: '账号不能为空', trigger: 'blur' }
],
password:[
{ required: true, message: '密码不能为空', trigger: 'blur' }
],
confirmPassword:[
{ required: true, message: '请再次输入密码', trigger: 'blur' },
{ validator: validateConfirmPassword, trigger: 'blur' }
]
}
};
}
@Data
public class TenantVo {
private String companyName;
private String companyNum;
private Long tenantType;
private String address;
private String logo;
private String username;
private String password;
/**
* 套餐
*/
private Long meal;
}
/**
* 公司入驻
* 思考:公司入驻的业务流程是什么样子的?要操作哪些表?先后顺序?
*
* t_tenant 租户表
*
* t_employee 存储租户的管理员账号信息
*
* t_tenant_meal 租户套餐表
*
* mybatis操作表不能级联操作,只能一张表一张表的操作
*
* @param tenantVo
*/
@Override
@Transient //同一个事物,要么全部成功,要么全部失败
public void register(TenantVo tenantVo) {
//向租户表中插入数据 返回租户id
Tenant tenant = new Tenant();
BeanUtils.copyProperties(tenantVo,tenant);
//初始化租户数据
tenant.setRegisterTime(System.currentTimeMillis());
tenant.setState(0);
baseMapper.insert(tenant);//mybatisplus默认会返回新增数据的主键
//向员工表中插入数据 - 租户管理员的用户和密码 - 返回员工id
Employee employee = new Employee();
BeanUtils.copyProperties(tenantVo,employee);
//设置这个员工的租户id
employee.setTenantId(tenant.getId());
employeeMapper.insert(employee);
//设置租户表中管理员的ID
//为了防止修改的时候数据丢失,我们先查询出来,在更改
tenant = baseMapper.selectById(tenant.getId());
tenant.setAdminId(employee.getId());
baseMapper.updateById(tenant);
//最后修改租户-套餐中间表
TenantMeal tenantMeal = new TenantMeal();
tenantMeal.setTenantId(tenant.getId());
tenantMeal.setMealId(tenantVo.getMeal());
//计算一年之后
long time = DateUtils.addYears(new Date(), 1).getTime();
tenantMeal.setExpireDate(time);//失效日期
tenantMealMapper.insert(tenantMeal);
}
package io.niker.hrm.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
*
*
*
*
* @author lidong
* @since 2020-03-30
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_tenant")
public class Tenant implements Serializable {
private static final long serialVersionUID=1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long tenantType;
@TableField("companyName")
private String companyName;
@TableField("companyNum")
private String companyNum;
@TableField("registerTime")
private Date registerTime;
private Integer state;
private String address;
private String logo;
private Long adminId;
/**
* 忽略的字段,生成增删改sql语句的时候,不生成这两个数据的sql
* mybatis的多对一
*/
@TableField(exist = false)
private Employee admin; // 租户管理员
@TableField(exist = false)
private TenantType type; // 机构类型
}
集群环境中必然要使用到分布式文件系统!!!
别人搭建好的(花钱)
阿里云、七牛云
自己搭建
hdfs、fastdfs【选择】
Tracker:调度和负载均衡
Storager:存储数据的
(1)用户请求Tracker,Tracker调度Storage,将Storage的ip和端口返回给client
(2)clinet发送数据到这个Storage中
文件上传
文件下载
pom.xml
<dependencies>
<dependency>
<groupId>io.nikergroupId>
<artifactId>hrm-dfs-commonartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
<dependency>
<groupId>cn.bestwugroupId>
<artifactId>fastdfs-client-javaartifactId>
<version>1.27version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>io.niker.hrm.DFSApplicationmainClass>
configuration>
plugin>
plugins>
build>
bootstrap.yml
#配置中心
spring:
cloud:
config:
discovery:
enabled: true
service-id: CONFIG-SERVER
name: application-dfs
profile: dev
#eureka客户端配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
配置中心 application-dfs-dev.yml
server:
port: 8001
#配置中心
spring:
application:
name: DFS-SERVICE
#eureka客户端配置
eureka:
instance:
instance-id: dfs-service:8001
prefer-ip-address: false
swagger的集成
package io.niker.hrm.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* swagger的配置
* swagger的目的:(1)通过html的方式展示项目中所有的接口(2)提供接口测试
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//对外暴露服务的包,以controller的方式暴露,所以就是controller的包.
.apis(RequestHandlerSelectors.basePackage("io.niker.hrm.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("文件服务api")
.description("文件服务接口文档说明")
.contact(new Contact("liodng", "", "[email protected]"))
.version("1.0")
.build();
}
}
启动类
略
网关的配置文件添加路由
server:
port: 1299
spring:
application:
name: ZUUL-SERVICE
#测试一波
eureka:
instance:
instance-id: zuul-service:1299 #服务实例的标识
prefer-ip-address: true #以ip注册
zuul:
ignored-services: "*"
prefix: /services
#路由配置
routes:
system:
path: /system/**
serviceId: HRM-SYSTEM
file:
path: /file/**
serviceId: DFS-SERVICE
网关的swagger配置
DocumentationConfig.java
package io.niker.hrm.util;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
@Component
@Primary
public class DocumentationConfig implements SwaggerResourcesProvider {
@Override
public List<SwaggerResource> get() {
List resources = new ArrayList<>();
resources.add(swaggerResource("资源管理", "/services/system/v2/api-docs", "2.0"));
resources.add(swaggerResource("文件管理", "/services/file/v2/api-docs", "2.0"));
resources.add(swaggerResource("课程管理", "/services/course/v2/api-docs", "2.0"));
resources.add(swaggerResource("页面静态化管理", "/services/page/v2/api-docs", "2.0"));
resources.add(swaggerResource("Es文档搜索管理", "/services/es/v2/api-docs", "2.0"));
resources.add(swaggerResource("缓存管理", "/services/cache/v2/api-docs", "2.0"));
resources.add(swaggerResource("用户管理", "/services/user/v2/api-docs", "2.0"));
resources.add(swaggerResource("短信管理", "/services/sms/v2/api-docs", "2.0"));
resources.add(swaggerResource("系统管理", "/services/system/v2/api-docs", "2.0"));
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
package io.niker.hrm.util;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
public class FastDfsApiOpr {
public static String CONF_FILENAME = FastDfsApiOpr.class.getClassLoader()
.getResource("fast_client.conf").getFile();
/**
* 上传文件
* @param file
* @param extName
* @return
*/
public static String upload(byte[] file,String extName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
NameValuePair nvp [] = new NameValuePair[]{
new NameValuePair("age", "18"),
new NameValuePair("sex", "male")
};
String fileIds[] = storageClient.upload_file(file,extName,nvp);
System.out.println(fileIds.length);
System.out.println("组名:" + fileIds[0]);
System.out.println("路径: " + fileIds[1]);
return "/"+fileIds[0]+"/"+fileIds[1];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 上传文件
* @param extName
* @return
*/
public static String upload(String path,String extName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
String fileIds[] = storageClient.upload_file(path, extName,null);
System.out.println(fileIds.length);
System.out.println("组名:" + fileIds[0]);
System.out.println("路径: " + fileIds[1]);
return "/"+fileIds[0]+"/"+fileIds[1];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 下载文件
* @param groupName
* @param fileName
* @return
*/
public static byte[] download(String groupName,String fileName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
byte[] b = storageClient.download_file(groupName, fileName);
return b;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// @Test
// public void testGetFileInfo(){
// try {
// ClientGlobal.init(conf_filename);
//
// TrackerClient tracker = new TrackerClient();
// TrackerServer trackerServer = tracker.getConnection();
// StorageServer storageServer = null;
//
// StorageClient storageClient = new StorageClient(trackerServer, storageServer);
// FileInfo fi = storageClient.get_file_info("group1", "M00/00/00/wKgRcFV_08OAK_KCAAAA5fm_sy874.conf");
// System.out.println(fi.getSourceIpAddr());
// System.out.println(fi.getFileSize());
// System.out.println(fi.getCreateTimestamp());
// System.out.println(fi.getCrc32());
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// @Test
// public void testGetFileMate(){
// try {
// ClientGlobal.init(conf_filename);
//
// TrackerClient tracker = new TrackerClient();
// TrackerServer trackerServer = tracker.getConnection();
// StorageServer storageServer = null;
//
// StorageClient storageClient = new StorageClient(trackerServer,
// storageServer);
// NameValuePair nvps [] = storageClient.get_metadata("group1", "M00/00/00/wKgRcFV_08OAK_KCAAAA5fm_sy874.conf");
// for(NameValuePair nvp : nvps){
// System.out.println(nvp.getName() + ":" + nvp.getValue());
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
/**
* 删除文件
* @param groupName
* @param fileName
*/
public static void delete(String groupName,String fileName){
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer,
storageServer);
int i = storageClient.delete_file(groupName,fileName);
System.out.println( i==0 ? "删除成功" : "删除失败:"+i);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("删除异常,"+e.getMessage());
}
}
}
fast_client.conf
tracker_server=FastDFS分布式文件系统的 ip地址:端口号
package io.niker.hrm.controller;
import io.niker.basic.util.AjaxResult;
import io.niker.hrm.util.FastDfsApiOpr;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
public class FileController {
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
public AjaxResult upload(MultipartFile file){
try {
byte[] bytes = file.getBytes();//上传的文件内容
//美女.png extName="png"
//文件名
String filename = file.getOriginalFilename();
//获取扩展名
int index = filename.lastIndexOf(".");
String extName = filename.substring(index+1);
String fileId = FastDfsApiOpr.upload(bytes, extName);
//要将fastdfs返回的file标识响应给前端
return AjaxResult.me().setSuccess(true).setMessage("上传成功!").setResultObj(fileId);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("上传失败!");
}
}
/**
* 文件删除
* 参数: /group1/M00/00/00/rBEAC16C9IKAQ6E3AAI8-cLFXhc547.png
*/
@GetMapping("/delete")
public AjaxResult delete(String fileId){
try {
String groupName = null;// group1
String fileName = null;// M00/00/00/rBEAC16C9IKAQ6E3AAI8-cLFXhc547.png
fileId = fileId.substring(1);// fileId = group1/M00/00/00/rBEAC16C9IKAQ6E3AAI8-cLFXhc547.png
int index = fileId.indexOf("/");
groupName = fileId.substring(0,index);
fileName = fileId.substring(index+1);
FastDfsApiOpr.delete(groupName,fileName);
return AjaxResult.me().setSuccess(true).setMessage("删除成功!");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("删除失败!"+e.getMessage());
}
}
}