This commit is contained in:
abu 2025-03-10 15:40:51 +08:00
commit 9f56a86116
125 changed files with 8945 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# 项目排除路径
/book-api/target/
/book-common/target/
/book-mapper/target/
/book-model/target/
/book-service/target/

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

32
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="book-model" />
<module name="book-common" />
<module name="book-service" />
<module name="book-api" />
<module name="book-mapper" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="mybatis-generator-database" target="1.5" />
<module name="mybatis-generator-for-imooc" target="1.5" />
</bytecodeTargetLevel>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="book-api" options="-parameters" />
<module name="book-common" options="-parameters" />
<module name="book-mapper" options="-parameters" />
<module name="book-model" options="-parameters" />
<module name="book-service" options="-parameters" />
<module name="imooc-red-book-dev" options="-parameters" />
</option>
</component>
</project>

16
.idea/encodings.xml generated Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/book-api/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/book-common/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/book-mapper/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/book-model/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/book-service/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/mybatis-generator-database-mysql8/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/mybatis-generator-database-mysql8/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/mybatis-generator-for-imooc/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/mybatis-generator-for-imooc/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

30
.idea/jarRepositories.xml generated Normal file
View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://maven.aliyun.com/repository/public" />
</remote-repository>
</component>
</project>

View File

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="mybatis-generator-for-imooc-1.0-SNAPSHOT">
<CLASSES>
<root url="jar://$PROJECT_DIR$/mybatis-generator-for-imooc/target/mybatis-generator-for-imooc-1.0-SNAPSHOT.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

20
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/mybatis-generator-for-imooc/pom.xml" />
</set>
</option>
<option name="workspaceImportForciblyTurnedOn" value="true" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

124
.idea/uiDesigner.xml generated Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

9
.idea/vlog-1.0.0.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

16
README.md Normal file
View File

@ -0,0 +1,16 @@
# douyin_dome
SpringBoot+Uniapp仿抖音短视频App
只用修改api模块下面的配置即可运行
Knife4j 接口文档通过访问 http://ip+prot/doc.html#/home 查看api
# 架构
![image](https://github.com/vercen/douyin_dome/assets/70558042/460d308a-0b6b-4918-a443-d2a6bf77e2dd)
![image](https://github.com/vercen/douyin_dome/assets/70558042/50b63912-39b0-4095-8c94-a731f59cb78b)
# 效果
![Screenshot_2023-06-01-11-51-48-628_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/60a656c8-6492-4d23-b569-7c8810ba507b)
![Screenshot_2023-06-01-11-52-17-198_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/63656269-ab10-4064-9b43-0e703a3d70b5)
![Screenshot_2023-06-01-11-52-20-875_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/9bd20a3c-2774-4a21-b0c1-b8a4945e2273)
![Screenshot_2023-06-01-11-52-24-302_uni UNI800FF13](https://github.com/vercen/douyin_dome/assets/70558042/118a8284-a64b-48f9-9caa-47308ec1c532)

71
book-api/pom.xml Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imooc</groupId>
<artifactId>imooc-red-book-dev</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<!--接口层-->
<artifactId>book-api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 服务注册与发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 分布式(微服务)配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 微服务的bootstrap -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>com.imooc</groupId>
<artifactId>book-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-springdoc-ui</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,23 @@
package com.imooc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import tk.mybatis.spring.annotation.MapperScan;
/**
* @author vercen
* @version 1.0
* @date 2023/5/20 14:25
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.imooc.mapper"})
@ComponentScan(basePackages = {"com.imooc","org.n3r.idworker"})
@EnableMongoRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,32 @@
package com.imooc.config;
import com.imooc.intercepter.PassportInterceptor;
import com.imooc.intercepter.UserTokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public PassportInterceptor passportInterceptor() {
return new PassportInterceptor();
}
@Bean
public UserTokenInterceptor userTokenInterceptor() {
return new UserTokenInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(passportInterceptor())
.addPathPatterns("/passport/getSMSCode");
registry.addInterceptor(userTokenInterceptor())
.addPathPatterns("/userInfo/modifyUserInfo")
.addPathPatterns("/userInfo/modifyImage");
}
}

View File

@ -0,0 +1,33 @@
package com.imooc.config;
import com.imooc.utils.MinIOUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Data
public class MinIOConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.fileHost}")
private String fileHost;
@Value("${minio.bucketName}")
private String bucketName;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Value("${minio.imgSize}")
private Integer imgSize;
@Value("${minio.fileSize}")
private Integer fileSize;
@Bean
public MinIOUtils creatMinioClient() {
return new MinIOUtils(endpoint, bucketName, accessKey, secretKey, imgSize, fileSize);
}
}

View File

@ -0,0 +1,40 @@
package com.imooc.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.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* @author vercen
* @version 1.0
* @date 2023/5/20 19:55
*/
@Configuration
@EnableSwagger2WebMvc
public class knife4jConfig {
@Bean
public Docket defaultApi2() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
//.title("swagger-bootstrap-ui-demo RESTful APIs")
.description("短视频实战接口文档")
.termsOfServiceUrl("http://www.xx.com/")
.contact(new Contact("lee", "http://www.imooc.com/", "abc@imooc.com"))
.version("1.0")
.build())
//分组名称
.groupName("2.X版本")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.imooc.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
}

View File

@ -0,0 +1,15 @@
package com.imooc.controller;
import com.imooc.utils.RedisOperator;
import org.springframework.beans.factory.annotation.Autowired;
//public class BaseController {
//
// @Autowired
// public RedisOperator redis;
//
// public static final String MOBILE_SMSCODE = "mobile:smscode";
// public static final String REDIS_USER_TOKEN = "redis_user_token";
// public static final String REDIS_USER_INFO = "redis_user_info";
//
//}

View File

@ -0,0 +1,46 @@
//package com.imooc.controller;
//
//import com.github.pagehelper.PageInfo;
//import com.imooc.utils.RedisOperator;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.validation.BindingResult;
//import org.springframework.validation.FieldError;
//
//import java.util.HashMap;
//import java.util.List;
//import java.util.Map;
//
//public class BaseInfoProperties {
//
// @Autowired
// public RedisOperator redis;
//
// public static final Integer COMMON_START_PAGE = 1;
// public static final Integer COMMON_PAGE_SIZE = 10;
//
// public static final String MOBILE_SMSCODE = "mobile:smscode";
// public static final String REDIS_USER_TOKEN = "redis_user_token";
// public static final String REDIS_USER_INFO = "redis_user_info";
//
//
// //我的关注总数
// public static final String REDIS_MY_FOLLOWS_COUNTS = "redis_my_follows_counts";
// // 我的粉丝总数
// public static final String REDIS_MY_FANS_COUNTS = "redis_my_fans_counts";
//
// // 视频和发布者获赞数
// public static final String REDIS_VLOG_BE_LIKED_COUNTS = "redis_vlog_be_liked_counts";
// public static final String REDIS_VLOGER_BE_LIKED_COUNTS = "redis_vloger_be_liked_counts";
//
// public PagedGridResult setterPagedGrid(List<?> list,
// Integer page) {
// PageInfo<?> pageList = new PageInfo<>(list);
// PagedGridResult gridResult = new PagedGridResult();
// gridResult.setRows(list);
// gridResult.setPage(page);
// gridResult.setRecords(pageList.getTotal());
// gridResult.setTotal(pageList.getPages());
// return gridResult;
// }
//
//}

View File

@ -0,0 +1,114 @@
package com.imooc.controller;
import com.imooc.base.BaseInfoProperties;
import com.imooc.bo.CommentBO;
import com.imooc.enums.MessageEnum;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.pojo.Comment;
import com.imooc.pojo.Vlog;
import com.imooc.service.CommentService;
import com.imooc.service.MsgService;
import com.imooc.service.VlogService;
import com.imooc.vo.CommentVO;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Api(tags = "CommentController 评论模块的接口")
@RequestMapping("comment")
@RestController
public class CommentController extends BaseInfoProperties {
@Autowired
private CommentService commentService;
@Autowired
private MsgService msgService;
@Autowired
private VlogService vlogService;
//
@PostMapping("create")
public GraceJSONResult create(@RequestBody @Valid CommentBO commentBO)
throws Exception {
CommentVO commentVO = commentService.createComment(commentBO);
return GraceJSONResult.ok(commentVO);
}
//
@GetMapping("counts")
public GraceJSONResult counts(@RequestParam String vlogId) {
String countsStr = redis.get(REDIS_VLOG_COMMENT_COUNTS + ":" + vlogId);
if (StringUtils.isBlank(countsStr)) {
countsStr = "0";
}
return GraceJSONResult.ok(Integer.valueOf(countsStr));
}
@GetMapping("list")
public GraceJSONResult list(@RequestParam String vlogId,
@RequestParam(defaultValue = "") String userId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
return GraceJSONResult.ok(
commentService.queryVlogComments(
vlogId,
userId,
page,
pageSize));
}
@DeleteMapping("delete")
public GraceJSONResult delete(@RequestParam String commentUserId,
@RequestParam String commentId,
@RequestParam String vlogId) {
commentService.deleteComment(commentUserId,
commentId,
vlogId);
return GraceJSONResult.ok();
}
@PostMapping("like")
public GraceJSONResult like(@RequestParam String commentId,
@RequestParam String userId) {
// 故意犯错bigkey
redis.incrementHash(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId, 1);
redis.setHashValue(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId, "1");
// redis.hset(REDIS_USER_LIKE_COMMENT, userId, "1");
// 系统消息点赞评论
Comment comment = commentService.getComment(commentId);
Vlog vlog = vlogService.getVlog(comment.getVlogId());
Map msgContent = new HashMap();
msgContent.put("vlogId", vlog.getId());
msgContent.put("vlogCover", vlog.getCover());
msgContent.put("commentId", commentId);
msgService.createMsg(userId,
comment.getCommentUserId(),
MessageEnum.LIKE_COMMENT.type,
msgContent);
return GraceJSONResult.ok();
}
@PostMapping("unlike")
public GraceJSONResult unlike(@RequestParam String commentId,
@RequestParam String userId) {
redis.decrementHash(REDIS_VLOG_COMMENT_LIKED_COUNTS, commentId, 1);
redis.hdel(REDIS_USER_LIKE_COMMENT, userId + ":" + commentId);
return GraceJSONResult.ok();
}
}

View File

@ -0,0 +1,106 @@
package com.imooc.controller;
import com.imooc.base.BaseInfoProperties;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.Users;
import com.imooc.service.FansService;
import com.imooc.service.UserService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Slf4j
@Api(tags = "FansController 粉丝相关业务功能的接口")
@RequestMapping("fans")
@RestController
public class FansController extends BaseInfoProperties {
@Autowired
private UserService userService;
@Autowired
private FansService fansService;
@PostMapping("follow")
public GraceJSONResult follow(@RequestParam String myId,
@RequestParam String vlogerId) {
// 判断两个id不能为空
if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR);
}
// 判断当前用户自己不能关注自己
if (myId.equalsIgnoreCase(vlogerId)) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_RESPONSE_NO_INFO);
}
// 判断两个id对应的用户是否存在
Users vloger = userService.getUser(vlogerId);
Users myInfo = userService.getUser(myId);
// fixme: 两个用户id的数据库查询后的判断是分开好还是合并判断好
if (myInfo == null || vloger == null) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_RESPONSE_NO_INFO);
}
//
// 保存粉丝关系到数据库
fansService.doFollow(myId, vlogerId);
// 博主的粉丝+1我的关注+1
redis.increment(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1);
redis.increment(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1);
// 我和博主的关联关系依赖redis不要存储数据库避免db的性能瓶颈
redis.set(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId, "1");
//
return GraceJSONResult.ok();
}
@PostMapping("cancel")
public GraceJSONResult cancel(@RequestParam String myId,
@RequestParam String vlogerId) {
// 删除业务的执行
fansService.doCancel(myId, vlogerId);
// 博主的粉丝-1我的关注-1
redis.decrement(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1);
redis.decrement(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1);
// 我和博主的关联关系依赖redis不要存储数据库避免db的性能瓶颈
redis.del(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId);
return GraceJSONResult.ok();
}
@GetMapping("queryDoIFollowVloger")
public GraceJSONResult queryDoIFollowVloger(@RequestParam String myId,
@RequestParam String vlogerId) {
return GraceJSONResult.ok(fansService.queryDoIFollowVloger(myId, vlogerId));
}
@GetMapping("queryMyFollows")
public GraceJSONResult queryMyFollows(@RequestParam String myId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
return GraceJSONResult.ok(
fansService.queryMyFollows(
myId,
page,
pageSize));
}
@GetMapping("queryMyFans")
public GraceJSONResult queryMyFans(@RequestParam String myId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
return GraceJSONResult.ok(
fansService.queryMyFans(
myId,
page,
pageSize));
}
}

View File

@ -0,0 +1,42 @@
package com.imooc.controller;
import com.imooc.config.MinIOConfig;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.utils.MinIOUtils;
import com.imooc.utils.SMSUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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;
@Slf4j
@Api(tags = "FileController 文件上传测试的接口")
@RestController
public class FileController {
@Autowired
private MinIOConfig minIOConfig;
@PostMapping("upload")
public GraceJSONResult upload(MultipartFile file) throws Exception {
String fileName = file.getOriginalFilename();
MinIOUtils.uploadFile(minIOConfig.getBucketName(),
fileName,
file.getInputStream());
String imgUrl = minIOConfig.getFileHost()
+ "/"
+ minIOConfig.getBucketName()
+ "/"
+ fileName;
return GraceJSONResult.ok(imgUrl);
}
}

View File

@ -0,0 +1,43 @@
package com.imooc.controller;
import com.imooc.base.BaseInfoProperties;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.mo.MessageMO;
import com.imooc.service.MsgService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j
@Api(tags = "MsgController 消息功能模块的接口")
@RequestMapping("msg")
@RestController
public class MsgController extends BaseInfoProperties {
@Autowired
private MsgService msgService;
@GetMapping("list")
public GraceJSONResult list(@RequestParam String userId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
// mongodb 从0分页区别于数据库
if (page == null) {
page = COMMON_START_PAGE_ZERO;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
List<MessageMO> list = msgService.queryList(userId, page, pageSize);
return GraceJSONResult.ok(list);
}
}

View File

@ -0,0 +1,95 @@
package com.imooc.controller;
import com.imooc.base.BaseInfoProperties;
import com.imooc.bo.RegistLoginBO;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.Users;
import com.imooc.service.UserService;
import com.imooc.utils.IPUtil;
import com.imooc.utils.SMSUtils;
import com.imooc.vo.UsersVO;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.UUID;
/**
* @author vercen
* @version 1.0
* @date 2023/5/25 10:47
*/
@Slf4j
@RestController
@RequestMapping("passport")
@Api(tags = "通行证,验证码登录注册")
public class PassportController extends BaseInfoProperties {
@Autowired
SMSUtils smsUtils;
@Autowired
UserService userService;
@PostMapping("getSMSCode")
public Object getSMSCode(@RequestParam String mobile, HttpServletRequest request) throws Exception {
if (StringUtils.isBlank(mobile)){
return GraceJSONResult.ok();
}
//TODO 获得用户ip 限制时间60s只能1次
String userIp=IPUtil.getRequestIp(request);
redis.setnx60s(MOBILE_SMSCODE+":"+userIp, userIp);
String code=(int)((Math.random()*9+1)*100000)+"";
smsUtils.sendSMS(mobile,code);
log.info(code);
redis.set(MOBILE_SMSCODE+":"+mobile, code,30*60);
//TODO 验证码放入redis
return GraceJSONResult.ok();
}
@PostMapping("login")
public Object login(@Valid @RequestBody RegistLoginBO registLoginBO){
String rediscode = redis.get(MOBILE_SMSCODE + ":" + registLoginBO.getMobile());
if (StringUtils.isBlank(rediscode)|| !rediscode.equalsIgnoreCase(registLoginBO.getSmsCode())){
System.out.println("rediscode"+rediscode);
System.out.println("registLoginBO.getMobile()"+registLoginBO.getSmsCode());
return GraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);
}
Users user = userService.queryMobileIsExist(registLoginBO.getMobile());
if (user==null){
user = userService.createUser(registLoginBO.getMobile());
}
String uToken = UUID.randomUUID().toString();
redis.set(REDIS_USER_TOKEN+":"+user.getId(),uToken);
//清除验证码
redis.del(MOBILE_SMSCODE+":"+user.getMobile());
//返回给前端
UsersVO usersVO = new UsersVO();
BeanUtils.copyProperties(user, usersVO);
usersVO.setUserToken(uToken);
return GraceJSONResult.ok(usersVO);
}
@PostMapping("logout")
public Object logout(@RequestParam String userId){
redis.del(REDIS_USER_TOKEN+":"+userId);
return GraceJSONResult.ok();
}
}

View File

@ -0,0 +1,66 @@
package com.imooc.controller;
import com.imooc.base.RabbitMQConfig;
import com.imooc.enums.MessageEnum;
import com.imooc.exceptions.GraceException;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.mo.MessageMO;
import com.imooc.service.MsgService;
import com.imooc.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class RabbitMQConsumer {
@Autowired
private MsgService msgService;
@RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})
public void watchQueue(String payload, Message message) {
log.info(payload);
MessageMO messageMO = JsonUtils.jsonToPojo(payload, MessageMO.class);
String routingKey = message.getMessageProperties().getReceivedRoutingKey();
log.info(routingKey);
// TODO: 下面这段代码可以优化一个地方是参数优化另外是枚举的判断优化
if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.FOLLOW_YOU.enValue)) {
msgService.createMsg(messageMO.getFromUserId(),
messageMO.getToUserId(),
MessageEnum.FOLLOW_YOU.type,
null);
} else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.LIKE_VLOG.enValue)) {
msgService.createMsg(messageMO.getFromUserId(),
messageMO.getToUserId(),
MessageEnum.FOLLOW_YOU.type,
messageMO.getMsgContent());
} else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.COMMENT_VLOG.enValue)) {
msgService.createMsg(messageMO.getFromUserId(),
messageMO.getToUserId(),
MessageEnum.COMMENT_VLOG.type,
messageMO.getMsgContent());
} else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.REPLY_YOU.enValue)) {
msgService.createMsg(messageMO.getFromUserId(),
messageMO.getToUserId(),
MessageEnum.REPLY_YOU.type,
messageMO.getMsgContent());
} else if (routingKey.equalsIgnoreCase("sys.msg." + MessageEnum.LIKE_COMMENT.enValue)) {
msgService.createMsg(messageMO.getFromUserId(),
messageMO.getToUserId(),
MessageEnum.LIKE_COMMENT.type,
messageMO.getMsgContent());
} else {
GraceException.display(ResponseStatusEnum.SYSTEM_OPERATION_ERROR);
}
}
}

View File

@ -0,0 +1,136 @@
package com.imooc.controller;
import com.imooc.base.BaseInfoProperties;
import com.imooc.bo.UpdatedUserBO;
import com.imooc.config.MinIOConfig;
import com.imooc.enums.FileTypeEnum;
import com.imooc.enums.UserInfoModifyType;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.pojo.Users;
import com.imooc.service.UserService;
import com.imooc.utils.MinIOUtils;
import com.imooc.utils.SMSUtils;
import com.imooc.vo.UsersVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* @author vercen
* @version 1.0
* @date 2023/5/20 14:32
*/
@RestController
@Slf4j
@Api(tags = "UserInfoController用户信息接口模块")
@RequestMapping("userInfo")
public class UserInfoController extends BaseInfoProperties {
@Autowired
UserService userService;
// @ResponseBody
@ApiOperation(value = "根据userId返回个人信息")
@GetMapping("query")
public Object query(@RequestParam String userId){
Users user = userService.getUser(userId);
UsersVO usersVO = new UsersVO();
BeanUtils.copyProperties(user, usersVO);
// 我的关注博主总数量
String myFollowsCountsStr = redis.get(REDIS_MY_FOLLOWS_COUNTS + ":" + userId);
// 我的粉丝总数
String myFansCountsStr = redis.get(REDIS_MY_FANS_COUNTS + ":" + userId);
// 用户获赞总数视频博主点赞/喜欢总和
// String likedVlogCountsStr = redis.get(REDIS_VLOG_BE_LIKED_COUNTS + ":" + userId);
String likedVlogerCountsStr = redis.get(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + userId);
Integer myFollowsCounts = 0;
Integer myFansCounts = 0;
Integer likedVlogCounts = 0;
Integer likedVlogerCounts = 0;
Integer totalLikeMeCounts = 0;
if (StringUtils.isNotBlank(myFollowsCountsStr)) {
myFollowsCounts = Integer.valueOf(myFollowsCountsStr);
}
if (StringUtils.isNotBlank(myFansCountsStr)) {
myFansCounts = Integer.valueOf(myFansCountsStr);
}
// if (StringUtils.isNotBlank(likedVlogCountsStr)) {
// likedVlogCounts = Integer.valueOf(likedVlogCountsStr);
// }
if (StringUtils.isNotBlank(likedVlogerCountsStr)) {
likedVlogerCounts = Integer.valueOf(likedVlogerCountsStr);
}
totalLikeMeCounts = likedVlogCounts + likedVlogerCounts;
usersVO.setMyFollowsCounts(myFollowsCounts);
usersVO.setMyFansCounts(myFansCounts);
usersVO.setTotalLikeMeCounts(totalLikeMeCounts);
//usersVO.setMyFansCounts((Integer) myFansCounts);
return GraceJSONResult.ok(usersVO);
}
@PostMapping("modifyUserInfo")
public GraceJSONResult modifyUserInfo(@RequestBody UpdatedUserBO updatedUserBO, @RequestParam Integer type) throws Exception {
UserInfoModifyType.checkUserInfoTypeIsRight(type);
Users newUserInfo = userService.updateUserInfo(updatedUserBO, type);
return GraceJSONResult.ok(newUserInfo);
}
@Autowired
private MinIOConfig minIOConfig;
@PostMapping("modifyImage")
public GraceJSONResult modifyImage(@RequestParam String userId,
@RequestParam Integer type,
MultipartFile file) throws Exception {
if (type != FileTypeEnum.BGIMG.type && type != FileTypeEnum.FACE.type) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_UPLOAD_FAILD);
}
String fileName = file.getOriginalFilename();
MinIOUtils.uploadFile(minIOConfig.getBucketName(),
fileName,
file.getInputStream());
String imgUrl = minIOConfig.getFileHost()
+ "/"
+ minIOConfig.getBucketName()
+ "/"
+ fileName;
// 修改图片地址到数据库
UpdatedUserBO updatedUserBO = new UpdatedUserBO();
updatedUserBO.setId(userId);
if (type == FileTypeEnum.BGIMG.type) {
updatedUserBO.setBgImg(imgUrl);
} else {
updatedUserBO.setFace(imgUrl);
}
Users users = userService.updateUserInfo(updatedUserBO);
return GraceJSONResult.ok(users);
}
}

View File

@ -0,0 +1,225 @@
package com.imooc.controller;
import com.imooc.base.BaseInfoProperties;
import com.imooc.bo.VlogBO;
import com.imooc.enums.YesOrNo;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.service.VlogService;
import com.imooc.utils.PagedGridResult;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;
@Slf4j
@Api(tags = "VlogController 短视频相关业务功能的接口")
@RequestMapping("vlog")
@RestController
@RefreshScope
public class VlogController extends BaseInfoProperties {
@Autowired
private VlogService vlogService;
@PostMapping("publish")
public GraceJSONResult publish(@RequestBody VlogBO vlogBO) {
// FIXME 作业校验VlogBO
vlogService.createVlog(vlogBO);
return GraceJSONResult.ok();
}
@GetMapping("indexList")
public GraceJSONResult indexList(@RequestParam(defaultValue = "") String userId,
@RequestParam(defaultValue = "") String search,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
if (page == null) {
page = COMMON_START_PAGE;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult gridResult = vlogService.getIndexVlogList(userId, search, page, pageSize);
return GraceJSONResult.ok(gridResult);
}
@GetMapping("detail")
public GraceJSONResult detail(@RequestParam(defaultValue = "") String userId,
@RequestParam String vlogId) {
return GraceJSONResult.ok(vlogService.getVlogDetailById(userId, vlogId));
}
@PostMapping("changeToPrivate")
public GraceJSONResult changeToPrivate(@RequestParam String userId,
@RequestParam String vlogId) {
vlogService.changeToPrivateOrPublic(userId,
vlogId,
YesOrNo.YES.type);
return GraceJSONResult.ok();
}
@PostMapping("changeToPublic")
public GraceJSONResult changeToPublic(@RequestParam String userId,
@RequestParam String vlogId) {
vlogService.changeToPrivateOrPublic(userId,
vlogId,
YesOrNo.NO.type);
return GraceJSONResult.ok();
}
@GetMapping("myPublicList")
public GraceJSONResult myPublicList(@RequestParam String userId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
if (page == null) {
page = COMMON_START_PAGE;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult gridResult = vlogService.queryMyVlogList(userId,
page,
pageSize,
YesOrNo.NO.type);
return GraceJSONResult.ok(gridResult);
}
@GetMapping("myPrivateList")
public GraceJSONResult myPrivateList(@RequestParam String userId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
if (page == null) {
page = COMMON_START_PAGE;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult gridResult = vlogService.queryMyVlogList(userId,
page,
pageSize,
YesOrNo.YES.type);
return GraceJSONResult.ok(gridResult);
}
@GetMapping("myLikedList")
public GraceJSONResult myLikedList(@RequestParam String userId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
if (page == null) {
page = COMMON_START_PAGE;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult gridResult = vlogService.getMyLikedVlogList(userId,
page,
pageSize);
return GraceJSONResult.ok(gridResult);
}
@Value(("${nacos.counts}"))
private Integer nacosConuts;
@PostMapping("like")
public GraceJSONResult like(@RequestParam String userId,
@RequestParam String vlogerId,
@RequestParam String vlogId) {
// 我点赞的视频关联关系保存到数据库
vlogService.userLikeVlog(userId, vlogId);
// 点赞后视频和视频发布者的获赞都会 +1
redis.increment(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + vlogerId, 1);
redis.increment(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId, 1);
// 我点赞的视频需要在redis中保存关联关系
redis.set(REDIS_USER_LIKE_VLOG + ":" + userId + ":" + vlogId, "1");
log.info("nacosConuts="+nacosConuts);
String countsStr = redis.get(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId);
Integer counts=0;
if (StringUtils.isNotBlank(countsStr)){
counts=Integer.valueOf(countsStr);
if (counts>=nacosConuts){
vlogService.flushCounts(vlogId, counts);
}
}
return GraceJSONResult.ok();
}
@PostMapping("unlike")
public GraceJSONResult unlike(@RequestParam String userId,
@RequestParam String vlogerId,
@RequestParam String vlogId) {
// 我取消点赞的视频关联关系删除
vlogService.userUnLikeVlog(userId, vlogId);
redis.decrement(REDIS_VLOGER_BE_LIKED_COUNTS + ":" + vlogerId, 1);
redis.decrement(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId, 1);
redis.del(REDIS_USER_LIKE_VLOG + ":" + userId + ":" + vlogId);
return GraceJSONResult.ok();
}
@PostMapping("totalLikedCounts")
public GraceJSONResult totalLikedCounts(@RequestParam String vlogId) {
return GraceJSONResult.ok(vlogService.getVlogBeLikedCounts(vlogId));
}
@GetMapping("followList")
public GraceJSONResult followList(@RequestParam String myId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
if (page == null) {
page = COMMON_START_PAGE;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult gridResult = vlogService.getMyFollowVlogList(myId,
page,
pageSize);
return GraceJSONResult.ok(gridResult);
}
@GetMapping("friendList")
public GraceJSONResult friendList(@RequestParam String myId,
@RequestParam Integer page,
@RequestParam Integer pageSize) {
if (page == null) {
page = COMMON_START_PAGE;
}
if (pageSize == null) {
pageSize = COMMON_PAGE_SIZE;
}
PagedGridResult gridResult = vlogService.getMyFriendVlogList(myId,
page,
pageSize);
return GraceJSONResult.ok(gridResult);
}
}

View File

@ -0,0 +1,47 @@
package com.imooc.intercepter;
import com.imooc.base.BaseInfoProperties;
import com.imooc.exceptions.GraceException;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.utils.IPUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class PassportInterceptor extends BaseInfoProperties implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// 获得用户的ip
String userIp = IPUtil.getRequestIp(request);
// 得到是否存在的判断
boolean keyIsExist = redis.keyIsExist(MOBILE_SMSCODE + ":" + userIp);
if (keyIsExist) {
GraceException.display(ResponseStatusEnum.SMS_NEED_WAIT_ERROR);
log.info("短信发送频率太大!");
return false;
}
/**
* true: 请求放行
* false: 请求拦截
*/
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}

View File

@ -0,0 +1,58 @@
package com.imooc.intercepter;
import com.imooc.base.BaseInfoProperties;
import com.imooc.exceptions.GraceException;
import com.imooc.grace.result.ResponseStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class UserTokenInterceptor extends BaseInfoProperties implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// 从header中获得用户id和token
String userId = request.getHeader("headerUserId");
String userToken = request.getHeader("headerUserToken");
// 判断header中用户id和token不能为空
if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(userToken)) {
String redisToken = redis.get(REDIS_USER_TOKEN + ":" + userId);
if (StringUtils.isBlank(redisToken)) {
GraceException.display(ResponseStatusEnum.UN_LOGIN);
return false;
} else {
// 比较token是否一致如果不一致表示用户在别的手机端登录
if (!redisToken.equalsIgnoreCase(userToken)) {
GraceException.display(ResponseStatusEnum.TICKET_INVALID);
return false;
}
}
} else {
GraceException.display(ResponseStatusEnum.UN_LOGIN);
return false;
}
/**
* true: 请求放行
* false: 请求拦截
*/
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}

View File

@ -0,0 +1,65 @@
server:
port: ${port:8099}
spring:
datasource: # 数据源的相关配置
type: com.zaxxer.hikari.HikariDataSource # 数据源的类型可以更改为其他的数据源配置比如druid
driver-class-name: com.mysql.cj.jdbc.Driver # mysql/MariaDB 的数据库驱动类名称
url: jdbc:mysql://182.92.182.217:3306/tiktok?characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
username: tiktok
password: Bc3T5AA2pBdt2FBk
hikari:
connection-timeout: 30000 # 等待连接池分配连接的最大时间毫秒超过这个时长还没有可用的连接则会抛出SQLException
minimum-idle: 5 # 最小连接数
maximum-pool-size: 20 # 最大连接数
auto-commit: true # 自动提交
idle-timeout: 600000 # 连接超时的最大时长毫秒超时则会被释放retired
pool-name: DataSourceHikariCP # 连接池的名字
max-lifetime: 18000000 # 连接池的最大生命时长毫秒超时则会被释放retired
connection-test-query: SELECT 1
redis:
host: 182.92.182.217
port: 6379
password: '!aw5)lJf'
database: 1 # 使用的数据库编号
jedis:
pool:
max-idle: 6 # 最大空闲连接
max-active: 32 # 连接池最大连接数
max-wait: 100 # 连接池最大阻塞等待时间, -1表示没有限制
min-idle: 4 # 最小空闲连接
timeout: 50000
data:
mongodb:
# uri: mongodb://root:root@192.168.1.202:27017
# database: imooc-red-book
uri: mongodb://admin:A1969bf8@82.156.121.2:37017/admin
rabbitmq:
host: 182.92.182.217
port: 5672
username: admin
password: 123123
virtual-host: imooc-red-book
application:
name: imooc-red-book-nacos
cloud:
nacos:
discovery:
server-addr: 182.92.182.217:8848 # nacos 所在的地址
# 打开监控
management:
endpoint:
web:
exposure:
include: '*'
# MinIO 配置
minio:
endpoint: http://82.156.121.2:29000 # MinIO服务地址
fileHost: http://82.156.121.2:29000 # 文件地址host
bucketName: bucket # 存储桶bucket名称
accessKey: NJ2GN2wLVkMnyrznbE9t # 用户名
secretKey: nrT3e3pRWF5HXQRiIxxDhq20eJ0YrN8lvx5p8bK6 # 密码
imgSize: 1024 # 图片大小限制单位m
fileSize: 1024 # 文件大小限制单位m

View File

@ -0,0 +1,65 @@
server:
port: 8080
spring:
datasource: # 数据源的相关配置
type: com.zaxxer.hikari.HikariDataSource # 数据源的类型可以更改为其他的数据源配置比如druid
driver-class-name: com.mysql.cj.jdbc.Driver # mysql/MariaDB 的数据库驱动类名称
url: jdbc:mysql://182.92.182.217/tiktok?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: tiktok
password: Bc3T5AA2pBdt2FBk
hikari:
connection-timeout: 30000 # 等待连接池分配连接的最大时间毫秒超过这个时长还没有可用的连接则会抛出SQLException
minimum-idle: 5 # 最小连接数
maximum-pool-size: 20 # 最大连接数
auto-commit: true # 自动提交
idle-timeout: 600000 # 连接超时的最大时长毫秒超时则会被释放retired
pool-name: DataSourceHikariCP # 连接池的名字
max-lifetime: 18000000 # 连接池的最大生命时长毫秒超时则会被释放retired
connection-test-query: SELECT 1
redis:
host: 182.92.182.217
port: 6379
password: '!aw5)lJf'
database: 1 # 使用的数据库编号
jedis:
pool:
max-idle: 6 # 最大空闲连接
max-active: 32 # 连接池最大连接数
max-wait: 100 # 连接池最大阻塞等待时间, -1表示没有限制
min-idle: 4 # 最小空闲连接
timeout: 50000
data:
mongodb:
uri: mongodb://admin:A1969bf8@82.156.121.2:37017/admin
rabbitmq:
host: 182.92.182.217
port: 5672
username: admin
password: 123123
virtual-host: imooc-red-book
application:
name: imooc-red-book-nacos
cloud:
nacos:
discovery:
server-addr: 182.92.182.217:8848 # nacos 所在的地址
# 打开监控
management:
endpoint:
web:
exposure:
include: '*'
# MinIO 配置
minio:
endpoint: http://82.156.121.2:29000 # MinIO服务地址
fileHost: http://82.156.121.2:29000 # 文件地址host
bucketName: bucket # 存储桶bucket名称
accessKey: NJ2GN2wLVkMnyrznbE9t # 用户名
secretKey: nrT3e3pRWF5HXQRiIxxDhq20eJ0YrN8lvx5p8bK6 # 密码
imgSize: 1024 # 图片大小限制单位m
fileSize: 1024 # 文件大小限制单位m

View File

@ -0,0 +1,43 @@
server:
# port: 8099
tomcat:
uri-encoding: UTF-8
max-swallow-size: -1 # tomcat默认大小2M超过2M的文件不会被捕获需要调整此处大小为100MB或者-1即可
spring:
application:
name: imooc-red-book-nacos
profiles:
active: dev
nacos:
counts: 10
banner:
location: classpath:banner/banner.txt
servlet:
multipart:
max-file-size: 1024MB # 文件上传大小限制,设置最大值,不能超过该值,否则报错
# max-file-size: 500KB # 文件上传大小限制,设置最大值,不能超过该值,否则报错
max-request-size: 1024MB # 文件最大请求限制,用于批量上传
# max-request-size: 500KB
nacos:
counts: 10
# 整合mybatis
mybatis:
type-aliases-package: com.imooc.pojo # 所有pojo类所在的包路径
mapper-locations: classpath:mapper/*.xml # mapper映射文件
# 通用mapper工具的配置
mapper:
mappers: com.imooc.my.mapper.MyMapper # 配置MyMapper包含了一些封装好的CRUD方法
not-empty: false # 在进行数据库操作的时候username != null 是否会追加 username != ''
identity: MYSQL
# 分页插件助手的配置
pagehelper:
helper-dialect: MYSQL
support-methods-arguments: true
# 日志级别
logging:
level:
root: info

View File

@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永无BUG 永不修改 //
////////////////////////////////////////////////////////////////////

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 KiB

View File

@ -0,0 +1,57 @@
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttjtttjttjjtjW#Li;;ijE#Ettttjttjjjtttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttjtttLGtWtttt#i;itttttttjti;tWtttjWtDEjtttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttjjjttfjLjWtEjjtjtjttttttjjtjttLWt;jEjjttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttDf;tjt;jWjjfLtttttttttttttttttttLDjjjjEtjj#ELttttttttttttttttttttttttttttt
tttttttttttttttttttttttt#DjGjfjtjjtjjfLttttttttttttttttttjL#jjjjtttjtfLGfjtttttttttttttttttttttttttt
tttttttttttttttttttttttttjfLjGttWjjjjLLtttttttttttttttttttLEjjjjjtttjjjjDjtttttttttttttttttttttttttt
tttttttttttttttttttttttttjjjjDttLjjjjLLttttttttttttttttttjLLjLjjjttijjjjLjtttttttttttttttttttttttttt
tttttttttttttttttttttttttjjjjjtttjjjfLLtttttttWEttf jtttttLDjLjjjjttEjfjLttttttttttttttttttttttttttt
ttttttttttttttttttttttttijjjjjtjDjjjjLLjttttjG GL :jttttLWjjjjttKjWjKjKttttttttttttttttttttttttttt
ttttttttttttttttttttttttijjjWjGjfjLjjLLjttttt,. ftttjLGjjtttj;jjj#jKjtttttttttttttttttttttttttt
ttttttttttttttttttttttttEj#ffjjjfjjjWfLfjtttttf KtttttfLL;jjffjjLjjjjjttttttttttttttttttttttttttt
tttttttttttttttttttttttttjjtjjjjjfLj#fLftttttjf tttttLLL#fjfjjjfjKjfttjttttttttttttttttttttttttt
tttttttttttttttttttttttttDjjjjjjLjGj#LLLttttjD . . .jtttLLLWGGffjjjGjtjtttttttttttttttttttttttttttt
tttttttttttttttttttttttttj;jjjjGLLDt#LLLtjjtjK Ej jtttLLLWjKLLLjjjjWttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttjGLLLLLLWKGLLttjtEWL;;;fKKjtttfWEWDLfLLLGWttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttfLLLfLGLD,,;ttjtttttti;;#LGLLLL#jttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttD::.#G;;jtjjjtttttjjtjtti;W:,:Wtttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttt;EjW,jtjjjjttjjttjtjtjjjjtj,Lj;jttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttE;;tjjtjjjKLLLLLLLLLGKjtjtjLLiWjttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttf,tjjttWLLLfLLLLLLLLfLfLKjtLLLfjttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttj,jjttEfLLLLLLLLLLLLLLLLLLLELLLLLttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttjittjtfLLLLLLLLfDEKDLfLfLfLfLLfLLLWtttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttjjffLLLLEGfjjjfjjjjjjGjKLLLfLfLLftjtttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttjjjLLLLKfjj;j;;;;;;;;,;jfjWLLLfLfLtttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttKLLLKf;ifj;i;;;;;;;j.E;;fLLLLGLLtttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttjtjLLLEG,;DWKWi;;;;;;;WWKE;;LfLLLLGtttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttWELLLLL;; WKKD;;;;;;jKKK.;;LLLLLWftttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttffLLLL:;EWKW,,;Di,;;KWKf;;fLLLLLjtttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttWLLLLLE;,E.;;;;;,;;;;tDi;#LLLLfDttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttKLLLLL;;;;;;;;tK,L;;;;;;LLLLfLtttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttjLLLLW,;;;;;EEED;;;;;;WLLLDtttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttjtKEL,;;;;;EjjW;;;;;KtEGjjjttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttjtttttW,,;;jttj,i;tWKffKfjtttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttDLjttfGWtjti,;Kjttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttDjittfj;,;;D;;;;ttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttE;;EEjWi;DGKj,iEjtjttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttt;,;;WWt;;;Dtttfttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttt;t;;;;;;;;;;Gtttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttjj,K;;;;;;;;;;;;jttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttjf;;j;;;;;;;;;;;;tttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttftGKE;;,;,,;;;;;ijttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttEfijDGGGGGGGGGGGKjttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttfjtGGGGGGGGGGEDWtttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttfEEDEEEEEEEKttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttLDEWWEEEttttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttjtttKWjtKWjttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttEjtjjijtttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttK,Gttf,fDtttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttWjD;tt;,fWtttttttttttttttttttttttttttttttttttttttttttttt
ttttttttttttttttttttttttttttttttttttttttttttttjttttttttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt

View File

@ -0,0 +1,8 @@
spring:
application:
name: imooc-red-book-nacos
cloud:
nacos:
config:
server-addr: 182.92.182.217:8848
file-extension: yaml

116
book-common/pom.xml Normal file
View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imooc</groupId>
<artifactId>imooc-red-book-dev</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>book-common</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 引入SpringBoot 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 引入 redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 引入 RabbitMQ 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- lombok工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- apache 工具类 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!-- google 工具类 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- joda-time 时间工具 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<!--腾讯云短信-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.270</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.2.1</version>
</dependency>
<!--<dependency>-->
<!-- <groupId>com.aliyun</groupId>-->
<!-- <artifactId>dysmsapi20170525</artifactId>-->
<!-- <version>2.0.23</version>-->
<!--</dependency>-->
</dependencies>
</project>

View File

@ -0,0 +1,17 @@
package com.imooc.enums;
/**
* @Desc: 文件类型 枚举
*/
public enum FileTypeEnum {
BGIMG(1, "用户背景图"),
FACE(2, "用户头像");
public final Integer type;
public final String value;
FileTypeEnum(Integer type, String value) {
this.type = type;
this.value = value;
}
}

View File

@ -0,0 +1,22 @@
package com.imooc.enums;
/**
* @Desc: 消息类型
*/
public enum MessageEnum {
FOLLOW_YOU(1, "关注", "follow"),
LIKE_VLOG(2, "点赞视频", "likeVideo"),
COMMENT_VLOG(3, "评论视频", "comment"),
REPLY_YOU(4, "回复评论", "replay"),
LIKE_COMMENT(5, "点赞评论", "likeComment");
public final Integer type;
public final String value;
public final String enValue;
MessageEnum(Integer type, String value, String enValue) {
this.type = type;
this.value = value;
this.enValue = enValue;
}
}

View File

@ -0,0 +1,18 @@
package com.imooc.enums;
/**
* @Desc: 性别 枚举
*/
public enum Sex {
woman(0, ""),
man(1, ""),
secret(2, "保密");
public final Integer type;
public final String value;
Sex(Integer type, String value) {
this.type = type;
this.value = value;
}
}

View File

@ -0,0 +1,35 @@
package com.imooc.enums;
import com.imooc.exceptions.GraceException;
import com.imooc.grace.result.ResponseStatusEnum;
/**
* @Desc: 修改用户信息类型 枚举
*/
public enum UserInfoModifyType {
NICKNAME(1, "昵称"),
IMOOCNUM(2, "慕课号"),
SEX(3, "性别"),
BIRTHDAY(4, "生日"),
LOCATION(5, "所在地"),
DESC(6, "简介");
public final Integer type;
public final String value;
UserInfoModifyType(Integer type, String value) {
this.type = type;
this.value = value;
}
public static void checkUserInfoTypeIsRight(Integer type) {
if (type != UserInfoModifyType.NICKNAME.type &&
type != UserInfoModifyType.IMOOCNUM.type &&
type != UserInfoModifyType.SEX.type &&
type != UserInfoModifyType.BIRTHDAY.type &&
type != UserInfoModifyType.LOCATION.type &&
type != UserInfoModifyType.DESC.type) {
GraceException.display(ResponseStatusEnum.USER_INFO_UPDATED_ERROR);
}
}
}

View File

@ -0,0 +1,17 @@
package com.imooc.enums;
/**
* @Desc: 是否 枚举
*/
public enum YesOrNo {
NO(0, ""),
YES(1, "");
public final Integer type;
public final String value;
YesOrNo(Integer type, String value) {
this.type = type;
this.value = value;
}
}

View File

@ -0,0 +1,14 @@
package com.imooc.exceptions;
import com.imooc.grace.result.ResponseStatusEnum;
/**
* 优雅的处理异常统一封装
*/
public class GraceException {
public static void display(ResponseStatusEnum responseStatusEnum) {
throw new MyCustomException(responseStatusEnum);
}
}

View File

@ -0,0 +1,58 @@
package com.imooc.exceptions;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 统一异常拦截处理
* 可以针对异常的类型进行捕获然后返回json信息到前端
*/
@ControllerAdvice
public class GraceExceptionHandler {
@ExceptionHandler(MyCustomException.class)
@ResponseBody
public GraceJSONResult returnMyException(MyCustomException e) {
//e.printStackTrace();
return GraceJSONResult.exception(e.getResponseStatusEnum());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public GraceJSONResult returnMethodArgumentNotValid(MethodArgumentNotValidException e) {
BindingResult result = e.getBindingResult();
Map<String, String> map = getErrors(result);
return GraceJSONResult.errorMap(map);
}
@ExceptionHandler(MaxUploadSizeExceededException.class)
@ResponseBody
public GraceJSONResult returnMaxUploadSize(MaxUploadSizeExceededException e) {
// e.printStackTrace();
return GraceJSONResult.errorCustom(ResponseStatusEnum.FILE_MAX_SIZE_2MB_ERROR);
}
public Map<String, String> getErrors(BindingResult result) {
Map<String, String> map = new HashMap<>();
List<FieldError> errorList = result.getFieldErrors();
for (FieldError ff : errorList) {
// 错误所对应的属性字段名
String field = ff.getField();
// 错误的信息
String msg = ff.getDefaultMessage();
map.put(field, msg);
}
return map;
}
}

View File

@ -0,0 +1,28 @@
package com.imooc.exceptions;
import com.imooc.grace.result.ResponseStatusEnum;
/**
* 自定义异常
* 目的统一处理异常信息
* 便于解耦拦截器service与controller 异常错误的解耦
* 不会被service返回的类型而限制
*/
public class MyCustomException extends RuntimeException {
private ResponseStatusEnum responseStatusEnum;
public MyCustomException(ResponseStatusEnum responseStatusEnum) {
super("异常状态码为:" + responseStatusEnum.status()
+ ";具体异常信息为:" + responseStatusEnum.msg());
this.responseStatusEnum = responseStatusEnum;
}
public ResponseStatusEnum getResponseStatusEnum() {
return responseStatusEnum;
}
public void setResponseStatusEnum(ResponseStatusEnum responseStatusEnum) {
this.responseStatusEnum = responseStatusEnum;
}
}

View File

@ -0,0 +1,153 @@
package com.imooc.grace.result;
import java.util.Map;
/**
* 自定义响应数据类型枚举升级版本
*
* @Title: IMOOCJSONResult.java
* @Package com.imooc.utils
* @Description: 自定义响应数据结构
* 本类可提供给 H5/ios/安卓/公众号/小程序 使用
* 前端接受此类数据json object)可自行根据业务去实现相关功能
*
* @Copyright: Copyright (c) 2020
* @Company: www.imooc.com
* @author 慕课网 - 风间影月
* @version V2.0
*/
public class GraceJSONResult {
// 响应业务状态码
private Integer status;
// 响应消息
private String msg;
// 是否成功
private Boolean success;
// 响应数据可以是Object也可以是List或Map等
private Object data;
/**
* 成功返回带有数据的直接往OK方法丢data数据即可
* @param data
* @return
*/
public static GraceJSONResult ok(Object data) {
return new GraceJSONResult(data);
}
/**
* 成功返回不带有数据的直接调用ok方法data无须传入其实就是null
* @return
*/
public static GraceJSONResult ok() {
return new GraceJSONResult(ResponseStatusEnum.SUCCESS);
}
public GraceJSONResult(Object data) {
this.status = ResponseStatusEnum.SUCCESS.status();
this.msg = ResponseStatusEnum.SUCCESS.msg();
this.success = ResponseStatusEnum.SUCCESS.success();
this.data = data;
}
/**
* 错误返回直接调用error方法即可当然也可以在ResponseStatusEnum中自定义错误后再返回也都可以
* @return
*/
public static GraceJSONResult error() {
return new GraceJSONResult(ResponseStatusEnum.FAILED);
}
/**
* 错误返回map中包含了多条错误信息可以用于表单验证把错误统一的全部返回出去
* @param map
* @return
*/
public static GraceJSONResult errorMap(Map map) {
return new GraceJSONResult(ResponseStatusEnum.FAILED, map);
}
/**
* 错误返回直接返回错误的消息
* @param msg
* @return
*/
public static GraceJSONResult errorMsg(String msg) {
return new GraceJSONResult(ResponseStatusEnum.FAILED, msg);
}
/**
* 错误返回token异常一些通用的可以在这里统一定义
* @return
*/
public static GraceJSONResult errorTicket() {
return new GraceJSONResult(ResponseStatusEnum.TICKET_INVALID);
}
/**
* 自定义错误范围需要传入一个自定义的枚举可以到[ResponseStatusEnum.java[中自定义后再传入
* @param responseStatus
* @return
*/
public static GraceJSONResult errorCustom(ResponseStatusEnum responseStatus) {
return new GraceJSONResult(responseStatus);
}
public static GraceJSONResult exception(ResponseStatusEnum responseStatus) {
return new GraceJSONResult(responseStatus);
}
public GraceJSONResult(ResponseStatusEnum responseStatus) {
this.status = responseStatus.status();
this.msg = responseStatus.msg();
this.success = responseStatus.success();
}
public GraceJSONResult(ResponseStatusEnum responseStatus, Object data) {
this.status = responseStatus.status();
this.msg = responseStatus.msg();
this.success = responseStatus.success();
this.data = data;
}
public GraceJSONResult(ResponseStatusEnum responseStatus, String msg) {
this.status = responseStatus.status();
this.msg = msg;
this.success = responseStatus.success();
}
public GraceJSONResult() {
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
}

View File

@ -0,0 +1,135 @@
package com.imooc.grace.result;
/**
*
* @Title: IMOOCJSONResult.java
* @Package com.imooc.utils
* @Description: 自定义响应数据结构
* 本类可提供给 H5/ios/安卓/公众号/小程序 使用
* 前端接受此类数据json object)可自行根据业务去实现相关功能
*
* 200表示成功
* 500表示错误错误信息在msg字段中
* 501bean验证错误不管多少个错误都以map形式返回
* 502拦截器拦截到用户token出错
* 555异常抛出信息
* 556: 用户qq校验异常
* 557: 校验用户是否在CAS登录用户门票的校验
* @Copyright: Copyright (c) 2020
* @Company: www.imooc.com
* @author 慕课网 - 风间影月
* @version V1.0
*/
public class IMOOCJSONResult {
// 响应业务状态
private Integer status;
// 响应消息
private String msg;
// 响应中的数据
private Object data;
private String ok; // 不使用
public static IMOOCJSONResult build(Integer status, String msg, Object data) {
return new IMOOCJSONResult(status, msg, data);
}
public static IMOOCJSONResult build(Integer status, String msg, Object data, String ok) {
return new IMOOCJSONResult(status, msg, data, ok);
}
public static IMOOCJSONResult ok(Object data) {
return new IMOOCJSONResult(data);
}
public static IMOOCJSONResult ok() {
return new IMOOCJSONResult(null);
}
public static IMOOCJSONResult errorMsg(String msg) {
return new IMOOCJSONResult(500, msg, null);
}
public static IMOOCJSONResult errorUserTicket(String msg) {
return new IMOOCJSONResult(557, msg, null);
}
public static IMOOCJSONResult errorMap(Object data) {
return new IMOOCJSONResult(501, "error", data);
}
public static IMOOCJSONResult errorTokenMsg(String msg) {
return new IMOOCJSONResult(502, msg, null);
}
public static IMOOCJSONResult errorException(String msg) {
return new IMOOCJSONResult(555, msg, null);
}
public static IMOOCJSONResult errorUserQQ(String msg) {
return new IMOOCJSONResult(556, msg, null);
}
public IMOOCJSONResult() {
}
public IMOOCJSONResult(Integer status, String msg, Object data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public IMOOCJSONResult(Integer status, String msg, Object data, String ok) {
this.status = status;
this.msg = msg;
this.data = data;
this.ok = ok;
}
public IMOOCJSONResult(Object data) {
this.status = 200;
this.msg = "OK";
this.data = data;
}
public Boolean isOK() {
return this.status == 200;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getOk() {
return ok;
}
public void setOk(String ok) {
this.ok = ok;
}
}

View File

@ -0,0 +1,105 @@
package com.imooc.grace.result;
/**
* 响应结果枚举用于提供给GraceJSONResult返回给前端的
* 本枚举类中包含了很多的不同的状态码供使用可以自定义
* 便于更优雅的对状态码进行管理一目了然
*/
public enum ResponseStatusEnum {
SUCCESS(200, true, "操作成功!"),
FAILED(500, false, "操作失败!"),
// 50x
UN_LOGIN(501,false,"请登录后再继续操作!"),
TICKET_INVALID(502,false,"会话失效,请重新登录!"),
NO_AUTH(503,false,"您的权限不足,无法继续操作!"),
MOBILE_ERROR(504,false,"短信发送失败,请稍后重试!"),
SMS_NEED_WAIT_ERROR(505,false,"短信发送太快啦~请稍后再试!"),
SMS_CODE_ERROR(506,false,"验证码过期或不匹配,请稍后再试!"),
USER_FROZEN(507,false,"用户已被冻结,请联系管理员!"),
USER_UPDATE_ERROR(508,false,"用户信息更新失败,请联系管理员!"),
USER_INACTIVE_ERROR(509,false,"请前往[账号设置]修改信息激活后再进行后续操作!"),
USER_INFO_UPDATED_ERROR(5091,false,"用户信息修改失败!"),
USER_INFO_UPDATED_NICKNAME_EXIST_ERROR(5092,false,"昵称已经存在!"),
USER_INFO_UPDATED_IMOOCNUM_EXIST_ERROR(5092,false,"慕课号已经存在!"),
USER_INFO_CANT_UPDATED_IMOOCNUM_ERROR(5092,false,"慕课号无法修改!"),
FILE_UPLOAD_NULL_ERROR(510,false,"文件不能为空,请选择一个文件再上传!"),
FILE_UPLOAD_FAILD(511,false,"文件上传失败!"),
FILE_FORMATTER_FAILD(512,false,"文件图片格式不支持!"),
FILE_MAX_SIZE_500KB_ERROR(5131,false,"仅支持500kb大小以下的图片上传"),
FILE_MAX_SIZE_2MB_ERROR(5132,false,"仅支持2MB大小以下的图片上传"),
FILE_NOT_EXIST_ERROR(514,false,"你所查看的文件不存在!"),
USER_STATUS_ERROR(515,false,"用户状态参数出错!"),
USER_NOT_EXIST_ERROR(516,false,"用户不存在!"),
// 自定义系统级别异常 54x
SYSTEM_INDEX_OUT_OF_BOUNDS(541, false, "系统错误,数组越界!"),
SYSTEM_ARITHMETIC_BY_ZERO(542, false, "系统错误,无法除零!"),
SYSTEM_NULL_POINTER(543, false, "系统错误,空指针!"),
SYSTEM_NUMBER_FORMAT(544, false, "系统错误,数字转换异常!"),
SYSTEM_PARSE(545, false, "系统错误,解析异常!"),
SYSTEM_IO(546, false, "系统错误IO输入输出异常"),
SYSTEM_FILE_NOT_FOUND(547, false, "系统错误,文件未找到!"),
SYSTEM_CLASS_CAST(548, false, "系统错误,类型强制转换错误!"),
SYSTEM_PARSER_ERROR(549, false, "系统错误,解析出错!"),
SYSTEM_DATE_PARSER_ERROR(550, false, "系统错误,日期解析出错!"),
// admin 管理系统 56x
ADMIN_USERNAME_NULL_ERROR(561, false, "管理员登录名不能为空!"),
ADMIN_USERNAME_EXIST_ERROR(562, false, "管理员登录名已存在!"),
ADMIN_NAME_NULL_ERROR(563, false, "管理员负责人不能为空!"),
ADMIN_PASSWORD_ERROR(564, false, "密码不能为空后者两次输入不一致!"),
ADMIN_CREATE_ERROR(565, false, "添加管理员失败!"),
ADMIN_PASSWORD_NULL_ERROR(566, false, "密码不能为空!"),
ADMIN_NOT_EXIT_ERROR(567, false, "管理员不存在或密码错误!"),
ADMIN_FACE_NULL_ERROR(568, false, "人脸信息不能为空!"),
ADMIN_FACE_LOGIN_ERROR(569, false, "人脸识别失败,请重试!"),
CATEGORY_EXIST_ERROR(570, false, "文章分类已存在,请换一个分类名!"),
// 媒体中心 相关错误 58x
ARTICLE_COVER_NOT_EXIST_ERROR(580, false, "文章封面不存在,请选择一个!"),
ARTICLE_CATEGORY_NOT_EXIST_ERROR(581, false, "请选择正确的文章领域!"),
ARTICLE_CREATE_ERROR(582, false, "创建文章失败,请重试或联系管理员!"),
ARTICLE_QUERY_PARAMS_ERROR(583, false, "文章列表查询参数错误!"),
ARTICLE_DELETE_ERROR(584, false, "文章删除失败!"),
ARTICLE_WITHDRAW_ERROR(585, false, "文章撤回失败!"),
ARTICLE_REVIEW_ERROR(585, false, "文章审核出错!"),
ARTICLE_ALREADY_READ_ERROR(586, false, "文章重复阅读!"),
// 人脸识别错误代码
FACE_VERIFY_TYPE_ERROR(600, false, "人脸比对验证类型不正确!"),
FACE_VERIFY_LOGIN_ERROR(601, false, "人脸登录失败!"),
// 系统错误未预期的错误 555
SYSTEM_ERROR(555, false, "系统繁忙,请稍后再试!"),
SYSTEM_OPERATION_ERROR(556, false, "操作失败,请重试或联系管理员"),
SYSTEM_RESPONSE_NO_INFO(557, false, ""),
SYSTEM_ERROR_GLOBAL(558, false, "全局降级:系统繁忙,请稍后再试!"),
SYSTEM_ERROR_FEIGN(559, false, "客户端Feign降级系统繁忙请稍后再试"),
SYSTEM_ERROR_ZUUL(560, false, "请求系统过于繁忙,请稍后再试!");
// 响应业务状态
private Integer status;
// 调用是否成功
private Boolean success;
// 响应消息可以为成功或者失败的消息
private String msg;
ResponseStatusEnum(Integer status, Boolean success, String msg) {
this.status = status;
this.success = success;
this.msg = msg;
}
public Integer status() {
return status;
}
public Boolean success() {
return success;
}
public String msg() {
return msg;
}
}

View File

@ -0,0 +1,680 @@
package com.imooc.utils;
import org.apache.commons.lang3.StringUtils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
public class DateUtil {
/**
* Base ISO 8601 Date format yyyyMMdd i.e., 20021225 for the 25th day of December in the year 2002
*/
public static final String ISO_DATE_FORMAT = "yyyyMMdd";
/**
* Expanded ISO 8601 Date format yyyy-MM-dd i.e., 2002-12-25 for the 25th day of December in the year 2002
*/
public static final String ISO_EXPANDED_DATE_FORMAT = "yyyy-MM-dd";
/**
* yyyy-MM-dd hh:mm:ss
*/
public static String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String DATE_PATTERN = "yyyyMMddHHmmss";
/**
* 则个
*/
private static boolean LENIENT_DATE = false;
private static Random random = new Random();
private static final int ID_BYTES = 10;
public synchronized static String generateId() {
StringBuffer result = new StringBuffer();
result = result.append(System.currentTimeMillis());
for (int i = 0; i < ID_BYTES; i++) {
result = result.append(random.nextInt(10));
}
return result.toString();
}
protected static final float normalizedJulian(float JD) {
float f = Math.round(JD + 0.5f) - 0.5f;
return f;
}
/**
* Returns the Date from a julian. The Julian date will be converted to noon GMT,
* such that it matches the nearest half-integer (i.e., a julian date of 1.4 gets
* changed to 1.5, and 0.9 gets changed to 0.5.)
*
* @param JD the Julian date
* @return the Gregorian date
*/
public static final Date toDate(float JD) {
/* To convert a Julian Day Number to a Gregorian date, assume that it is for 0 hours, Greenwich time (so
* that it ends in 0.5). Do the following calculations, again dropping the fractional part of all
* multiplicatons and divisions. Note: This method will not give dates accurately on the
* Gregorian Proleptic Calendar, i.e., the calendar you get by extending the Gregorian
* calendar backwards to years earlier than 1582. using the Gregorian leap year
* rules. In particular, the method fails if Y<400. */
float Z = (normalizedJulian(JD)) + 0.5f;
float W = (int) ((Z - 1867216.25f) / 36524.25f);
float X = (int) (W / 4f);
float A = Z + 1 + W - X;
float B = A + 1524;
float C = (int) ((B - 122.1) / 365.25);
float D = (int) (365.25f * C);
float E = (int) ((B - D) / 30.6001);
float F = (int) (30.6001f * E);
int day = (int) (B - D - F);
int month = (int) (E - 1);
if (month > 12) {
month = month - 12;
}
int year = (int) (C - 4715); //(if Month is January or February) or C-4716 (otherwise)
if (month > 2) {
year--;
}
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1); // damn 0 offsets
c.set(Calendar.DATE, day);
return c.getTime();
}
/**
* Returns the days between two dates. Positive values indicate that
* the second date is after the first, and negative values indicate, well,
* the opposite. Relying on specific times is problematic.
*
* @param early the "first date"
* @param late the "second date"
* @return the days between the two dates
*/
public static final int daysBetween(Date early, Date late) {
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(early);
c2.setTime(late);
return daysBetween(c1, c2);
}
/**
* Returns the days between two dates. Positive values indicate that
* the second date is after the first, and negative values indicate, well,
* the opposite.
*
* @param early
* @param late
* @return the days between two dates.
*/
public static final int daysBetween(Calendar early, Calendar late) {
return (int) (toJulian(late) - toJulian(early));
}
/**
* 计算时间差
* @param startDate
* @param endDate
* @return
*/
public static final String timeBetween(Date startDate, Date endDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - startDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "" + hour + "小时" + min + "分钟";
}
/**
* Return a Julian date based on the input parameter. This is
* based from calculations found at
* <a href="http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html">Julian Day Calculations
* (Gregorian Calendar)</a>, provided by Bill Jeffrys.
* @param c a calendar instance
* @return the julian day number
*/
public static final float toJulian(Calendar c) {
int Y = c.get(Calendar.YEAR);
int M = c.get(Calendar.MONTH);
int D = c.get(Calendar.DATE);
int A = Y / 100;
int B = A / 4;
int C = 2 - A + B;
float E = (int) (365.25f * (Y + 4716));
float F = (int) (30.6001f * (M + 1));
float JD = C + D + E + F - 1524.5f;
return JD;
}
/**
* Return a Julian date based on the input parameter. This is
* based from calculations found at
* <a href="http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html">Julian Day Calculations
* (Gregorian Calendar)</a>, provided by Bill Jeffrys.
* @param date
* @return the julian day number
*/
public static final float toJulian(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return toJulian(c);
}
/**
* @param isoString
* @param fmt
* @param field Calendar.YEAR/Calendar.MONTH/Calendar.DATE
* @param amount
* @return
* @throws ParseException
*/
public static final String dateIncrease(String isoString, String fmt,
int field, int amount) {
try {
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
"GMT"));
cal.setTime(stringToDate(isoString, fmt, true));
cal.add(field, amount);
return dateToString(cal.getTime(), fmt);
} catch (Exception ex) {
return null;
}
}
/**
* Time Field Rolling function.
* Rolls (up/down) a single unit of time on the given time field.
*
* @param isoString
* @param field the time field.
* @param up Indicates if rolling up or rolling down the field value.
* @param expanded use formating char's
* @exception ParseException if an unknown field value is given.
*/
public static final String roll(String isoString, String fmt, int field,
boolean up) throws ParseException {
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
"GMT"));
cal.setTime(stringToDate(isoString, fmt));
cal.roll(field, up);
return dateToString(cal.getTime(), fmt);
}
/**
* Time Field Rolling function.
* Rolls (up/down) a single unit of time on the given time field.
*
* @param isoString
* @param field the time field.
* @param up Indicates if rolling up or rolling down the field value.
* @exception ParseException if an unknown field value is given.
*/
public static final String roll(String isoString, int field, boolean up) throws
ParseException {
return roll(isoString, DATETIME_PATTERN, field, up);
}
/**
* java.util.Date
* @param dateText
* @param format
* @param lenient
* @return
*/
public static Date stringToDate(String dateText, String format,
boolean lenient) {
if (dateText == null) {
return null;
}
DateFormat df = null;
try {
if (format == null) {
df = new SimpleDateFormat();
} else {
df = new SimpleDateFormat(format);
}
// setLenient avoids allowing dates like 9/32/2001
// which would otherwise parse to 10/2/2001
df.setLenient(false);
return df.parse(dateText);
} catch (ParseException e) {
return null;
}
}
/**
* @return Timestamp
*/
public static java.sql.Timestamp getCurrentTimestamp() {
return new java.sql.Timestamp(new Date().getTime());
}
/** java.util.Date
* @param dateText
* @param format
* @return
*/
public static Date stringToDate(String dateString, String format) {
return stringToDate(dateString, format, LENIENT_DATE);
}
/**
* java.util.Date
* @param dateText
*/
public static Date stringToDate(String dateString) {
return stringToDate(dateString, ISO_EXPANDED_DATE_FORMAT, LENIENT_DATE);
}
/**
* @return
* @param pattern
* @param date
*/
public static String dateToString(Date date, String pattern) {
if (date == null) {
return null;
}
try {
SimpleDateFormat sfDate = new SimpleDateFormat(pattern);
sfDate.setLenient(false);
return sfDate.format(date);
} catch (Exception e) {
return null;
}
}
/**
* yyyy-MM-dd
* @param date
* @return
*/
public static String dateToString(Date date) {
return dateToString(date, ISO_EXPANDED_DATE_FORMAT);
}
/**
* @return
*/
public static Date getCurrentDateTime() {
Calendar calNow = Calendar.getInstance();
Date dtNow = calNow.getTime();
return dtNow;
}
/**
*
* @param pattern
* @return
*/
public static String getCurrentDateString(String pattern) {
return dateToString(getCurrentDateTime(), pattern);
}
/**
* yyyy-MM-dd
* @return
*/
public static String getCurrentDateString() {
return dateToString(getCurrentDateTime(), ISO_EXPANDED_DATE_FORMAT);
}
/**
* 返回固定格式的当前时间
* yyyy-MM-dd hh:mm:ss
* @param date
* @return
*/
public static String dateToStringWithTime( ) {
return dateToString(new Date(), DATETIME_PATTERN);
}
/**
* yyyy-MM-dd hh:mm:ss
* @param date
* @return
*/
public static String dateToStringWithTime(Date date) {
return dateToString(date, DATETIME_PATTERN);
}
/**
*
* @param date
* @param days
* @return java.util.Date
*/
public static Date dateIncreaseByDay(Date date, int days) {
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
"GMT"));
cal.setTime(date);
cal.add(Calendar.DATE, days);
return cal.getTime();
}
/**
*
* @param date
* @param days
* @return java.util.Date
*/
public static Date dateIncreaseByMonth(Date date, int mnt) {
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
"GMT"));
cal.setTime(date);
cal.add(Calendar.MONTH, mnt);
return cal.getTime();
}
/**
*
* @param date
* @param mnt
* @return java.util.Date
*/
public static Date dateIncreaseByYear(Date date, int mnt) {
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone(
"GMT"));
cal.setTime(date);
cal.add(Calendar.YEAR, mnt);
return cal.getTime();
}
/**
*
* @param date yyyy-MM-dd
* @param days
* @return yyyy-MM-dd
*/
public static String dateIncreaseByDay(String date, int days) {
return dateIncreaseByDay(date, ISO_DATE_FORMAT, days);
}
/**
* @param date
* @param fmt
* @param days
* @return
*/
public static String dateIncreaseByDay(String date, String fmt, int days) {
return dateIncrease(date, fmt, Calendar.DATE, days);
}
/**
*
* @param src
* @param srcfmt
* @param desfmt
* @return
*/
public static String stringToString(String src, String srcfmt,
String desfmt) {
return dateToString(stringToDate(src, srcfmt), desfmt);
}
/**
*
* @param date
* @return string
*/
public static String getYear(Date date) {
SimpleDateFormat formater = new SimpleDateFormat(
"yyyy");
String cur_year = formater.format(date);
return cur_year;
}
/**
*
* @param date
* @return string
*/
public static String getMonth(Date date) {
SimpleDateFormat formater = new SimpleDateFormat(
"MM");
String cur_month = formater.format(date);
return cur_month;
}
/**
* @param date
* @return string
*/
public static String getDay(Date date) {
SimpleDateFormat formater = new SimpleDateFormat(
"dd");
String cur_day = formater.format(date);
return cur_day;
}
public static int getDayInt(Date date) {
SimpleDateFormat formater = new SimpleDateFormat(
"dd");
String cur_day = formater.format(date);
return Integer.valueOf(cur_day);
}
/**
* @param date
* @return string
*/
public static String getHour(Date date) {
SimpleDateFormat formater = new SimpleDateFormat(
"HH");
String cur_day = formater.format(date);
return cur_day;
}
public static int getMinsFromDate(Date dt) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(dt);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int min = cal.get(Calendar.MINUTE);
return ((hour * 60) + min);
}
/**
* Function to convert String to Date Object. If invalid input then current or next day date
* is returned (Added by Ali Naqvi on 2006-5-16).
* @param str String input in YYYY-MM-DD HH:MM[:SS] format.
* @param isExpiry boolean if set and input string is invalid then next day date is returned
* @return Date
*/
public static Date convertToDate(String str, boolean isExpiry) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date dt = null;
try {
dt = fmt.parse(str);
} catch (ParseException ex) {
Calendar cal = Calendar.getInstance();
if (isExpiry) {
cal.add(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
} else {
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
}
dt = cal.getTime();
}
return dt;
}
public static Date convertToDate(String str) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd hh:mm");
Date dt = null;
try {
dt = fmt.parse(str);
} catch (ParseException ex) {
dt = new Date();
}
return dt;
}
public static String dateFromat(Date date, int minute) {
String dateFormat = null;
int year = Integer.parseInt(getYear(date));
int month = Integer.parseInt(getMonth(date));
int day = Integer.parseInt(getDay(date));
int hour = minute / 60;
int min = minute % 60;
dateFormat = String.valueOf(year)
+
(month > 9 ? String.valueOf(month) :
"0" + String.valueOf(month))
+
(day > 9 ? String.valueOf(day) : "0" + String.valueOf(day))
+ " "
+
(hour > 9 ? String.valueOf(hour) : "0" + String.valueOf(hour))
+
(min > 9 ? String.valueOf(min) : "0" + String.valueOf(min))
+ "00";
return dateFormat;
}
public static String sDateFormat() {
return new SimpleDateFormat(DATE_PATTERN).format(Calendar.getInstance().getTime());
}
/**
*
* @Description: 获得本月的第一天日期
* @return
*
* @author leechenxiang
* @date 2017年5月31日 下午1:37:34
*/
public static String getFirstDateOfThisMonth() {
SimpleDateFormat format = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT);
Calendar calendarFirst = Calendar.getInstance();
calendarFirst = Calendar.getInstance();
calendarFirst.add(Calendar.MONTH, 0);
calendarFirst.set(Calendar.DAY_OF_MONTH, 1);
String firstDate = format.format(calendarFirst.getTime());
return firstDate;
}
/**
*
* @Description: 获得本月的最后一天日期
* @return
*
* @author leechenxiang
* @date 2017年5月31日 下午1:37:50
*/
public static String getLastDateOfThisMonth() {
SimpleDateFormat format = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT);
Calendar calendarLast = Calendar.getInstance();
calendarLast.setTime(new Date());
calendarLast.getActualMaximum(Calendar.DAY_OF_MONTH);
String lastDate = format.format(calendarLast.getTime());
return lastDate;
}
/**
* @Description: 判断字符串日期是否匹配指定的格式化日期
*/
public static boolean isValidDate(String strDate, String formatter) {
SimpleDateFormat sdf = null;
ParsePosition pos = new ParsePosition(0);
if (StringUtils.isBlank(strDate) || StringUtils.isBlank(formatter)) {
return false;
}
try {
sdf = new SimpleDateFormat(formatter);
sdf.setLenient(false);
Date date = sdf.parse(strDate, pos);
if (date == null) {
return false;
} else {
if (pos.getIndex() > sdf.format(date).length()) {
return false;
}
return true;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void main(String[] args)
{
// String timeDir=DateUtil.dateToString(new Date(),DateUtil.ISO_EXPANDED_DATE_FORMAT);
// System.out.println(timeDir);
boolean flag = DateUtil.isValidDate("1990-10-32", DateUtil.ISO_EXPANDED_DATE_FORMAT);
System.out.println(flag);
}
}

View File

@ -0,0 +1,77 @@
package com.imooc.utils;
/**
* 通用脱敏工具类
* 可用于
* 用户名
* 手机号
* 邮箱
* 地址等
*/
public class DesensitizationUtil {
private static final int SIZE = 6;
private static final String SYMBOL = "*";
public static void main(String[] args) {
String name = commonDisplay("慕课网");
String mobile = commonDisplay("13900000000");
String mail = commonDisplay("admin@imooc.com");
String address = commonDisplay("北京大运河东路888号");
System.out.println(name);
System.out.println(mobile);
System.out.println(mail);
System.out.println(address);
}
/**
* 通用脱敏方法
* @param value
* @return
*/
public static String commonDisplay(String value) {
if (null == value || "".equals(value)) {
return value;
}
int len = value.length();
int pamaone = len / 2;
int pamatwo = pamaone - 1;
int pamathree = len % 2;
StringBuilder stringBuilder = new StringBuilder();
if (len <= 2) {
if (pamathree == 1) {
return SYMBOL;
}
stringBuilder.append(SYMBOL);
stringBuilder.append(value.charAt(len - 1));
} else {
if (pamatwo <= 0) {
stringBuilder.append(value.substring(0, 1));
stringBuilder.append(SYMBOL);
stringBuilder.append(value.substring(len - 1, len));
} else if (pamatwo >= SIZE / 2 && SIZE + 1 != len) {
int pamafive = (len - SIZE) / 2;
stringBuilder.append(value.substring(0, pamafive));
for (int i = 0; i < SIZE; i++) {
stringBuilder.append(SYMBOL);
}
if ((pamathree == 0 && SIZE / 2 == 0) || (pamathree != 0 && SIZE % 2 != 0)) {
stringBuilder.append(value.substring(len - pamafive, len));
} else {
stringBuilder.append(value.substring(len - (pamafive + 1), len));
}
} else {
int pamafour = len - 2;
stringBuilder.append(value.substring(0, 1));
for (int i = 0; i < pamafour; i++) {
stringBuilder.append(SYMBOL);
}
stringBuilder.append(value.substring(len - 1, len));
}
}
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,37 @@
package com.imooc.utils;
import javax.servlet.http.HttpServletRequest;
/**
* 用户获得用户ip的工具类
*/
public class IPUtil {
/**
* 获取请求IP:
* 用户的真实IP不能使用request.getRemoteAddr()
* 这是因为可能会使用一些代理软件这样ip获取就不准确了
* 此外我们如果使用了多级LVS/Nginx反向代理的话ip需要从X-Forwarded-For中获得第一个非unknown的IP才是用户的有效ip
* @param request
* @return
*/
public static String getRequestIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}

View File

@ -0,0 +1,74 @@
package com.imooc.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
/**
*
* @Title: JsonUtils.java
* @Package com.imooc.utils
* @Description: json转换类
* Copyright: Copyright (c)
* Company: www.imooc.com
*
* @author imooc
*/
public class JsonUtils {
// 定义jackson对象
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 将对象转换成json字符串
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 将json结果集转化为对象
*
* @param jsonData json数据
* @param beanType 对象中的object类型
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成pojo对象list
* @param jsonData
* @param beanType
* @return
*/
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,432 @@
package com.imooc.utils;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
/**
* MinIO工具类
*/
@Slf4j
public class MinIOUtils {
private static MinioClient minioClient;
private static String endpoint;
private static String bucketName;
private static String accessKey;
private static String secretKey;
private static Integer imgSize;
private static Integer fileSize;
private static final String SEPARATOR = "/";
public MinIOUtils() {
}
public MinIOUtils(String endpoint, String bucketName, String accessKey, String secretKey, Integer imgSize, Integer fileSize) {
MinIOUtils.endpoint = endpoint;
MinIOUtils.bucketName = bucketName;
MinIOUtils.accessKey = accessKey;
MinIOUtils.secretKey = secretKey;
MinIOUtils.imgSize = imgSize;
MinIOUtils.fileSize = fileSize;
createMinioClient();
}
/**
* 创建基于Java端的MinioClient
*/
public void createMinioClient() {
try {
if (null == minioClient) {
log.info("开始创建 MinioClient...");
minioClient = MinioClient
.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
createBucket(bucketName);
log.info("创建完毕 MinioClient...");
}
} catch (Exception e) {
log.error("MinIO服务器异常{}", e);
}
}
/**
* 获取上传文件前缀路径
* @return
*/
public static String getBasisUrl() {
return endpoint + SEPARATOR + bucketName + SEPARATOR;
}
/****************************** Operate Bucket Start ******************************/
/**
* 启动SpringBoot容器的时候初始化Bucket
* 如果没有Bucket则创建
* @throws Exception
*/
private static void createBucket(String bucketName) throws Exception {
if (!bucketExists(bucketName)) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
}
}
/**
* 判断Bucket是否存在true存在false不存在
* @return
* @throws Exception
*/
public static boolean bucketExists(String bucketName) throws Exception {
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
}
/**
* 获得Bucket的策略
* @param bucketName
* @return
* @throws Exception
*/
public static String getBucketPolicy(String bucketName) throws Exception {
String bucketPolicy = minioClient
.getBucketPolicy(
GetBucketPolicyArgs
.builder()
.bucket(bucketName)
.build()
);
return bucketPolicy;
}
/**
* 获得所有Bucket列表
* @return
* @throws Exception
*/
public static List<Bucket> getAllBuckets() throws Exception {
return minioClient.listBuckets();
}
/**
* 根据bucketName获取其相关信息
* @param bucketName
* @return
* @throws Exception
*/
public static Optional<Bucket> getBucket(String bucketName) throws Exception {
return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
}
/**
* 根据bucketName删除Buckettrue删除成功 false删除失败文件或已不存在
* @param bucketName
* @throws Exception
*/
public static void removeBucket(String bucketName) throws Exception {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
}
/****************************** Operate Bucket End ******************************/
/****************************** Operate Files Start ******************************/
/**
* 判断文件是否存在
* @param bucketName 存储桶
* @param objectName 文件名
* @return
*/
public static boolean isObjectExist(String bucketName, String objectName) {
boolean exist = true;
try {
minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (Exception e) {
exist = false;
}
return exist;
}
/**
* 判断文件夹是否存在
* @param bucketName 存储桶
* @param objectName 文件夹名称
* @return
*/
public static boolean isFolderExist(String bucketName, String objectName) {
boolean exist = false;
try {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
for (Result<Item> result : results) {
Item item = result.get();
if (item.isDir() && objectName.equals(item.objectName())) {
exist = true;
}
}
} catch (Exception e) {
exist = false;
}
return exist;
}
/**
* 根据文件前缀查询文件
* @param bucketName 存储桶
* @param prefix 前缀
* @param recursive 是否使用递归查询
* @return MinioItem 列表
* @throws Exception
*/
public static List<Item> getAllObjectsByPrefix(String bucketName,
String prefix,
boolean recursive) throws Exception {
List<Item> list = new ArrayList<>();
Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
if (objectsIterator != null) {
for (Result<Item> o : objectsIterator) {
Item item = o.get();
list.add(item);
}
}
return list;
}
/**
* 获取文件流
* @param bucketName 存储桶
* @param objectName 文件名
* @return 二进制流
*/
public static InputStream getObject(String bucketName, String objectName) throws Exception {
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
}
/**
* 断点下载
* @param bucketName 存储桶
* @param objectName 文件名称
* @param offset 起始字节的位置
* @param length 要读取的长度
* @return 二进制流
*/
public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.offset(offset)
.length(length)
.build());
}
/**
* 获取路径下文件列表
* @param bucketName 存储桶
* @param prefix 文件名称
* @param recursive 是否递归查找false模拟文件夹结构查找
* @return 二进制流
*/
public static Iterable<Result<Item>> listObjects(String bucketName, String prefix,
boolean recursive) {
return minioClient.listObjects(
ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(prefix)
.recursive(recursive)
.build());
}
/**
* 使用MultipartFile进行文件上传
* @param bucketName 存储桶
* @param file 文件名
* @param objectName 对象名
* @param contentType 类型
* @return
* @throws Exception
*/
public static ObjectWriteResponse uploadFile(String bucketName, MultipartFile file,
String objectName, String contentType) throws Exception {
InputStream inputStream = file.getInputStream();
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.contentType(contentType)
.stream(inputStream, inputStream.available(), -1)
.build());
}
/**
* 上传本地文件
* @param bucketName 存储桶
* @param objectName 对象名称
* @param fileName 本地文件路径
*/
public static ObjectWriteResponse uploadFile(String bucketName, String objectName,
String fileName) throws Exception {
return minioClient.uploadObject(
UploadObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.filename(fileName)
.build());
}
/**
* 通过流上传文件
*
* @param bucketName 存储桶
* @param objectName 文件对象
* @param inputStream 文件流
*/
public static ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) throws Exception {
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(inputStream, inputStream.available(), -1)
.build());
}
/**
* 创建文件夹或目录
* @param bucketName 存储桶
* @param objectName 目录路径
*/
public static ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception {
return minioClient.putObject(
PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
.build());
}
/**
* 获取文件信息, 如果抛出异常则说明文件不存在
*
* @param bucketName 存储桶
* @param objectName 文件名称
*/
public static String getFileStatusInfo(String bucketName, String objectName) throws Exception {
return minioClient.statObject(
StatObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build()).toString();
}
/**
* 拷贝文件
*
* @param bucketName 存储桶
* @param objectName 文件名
* @param srcBucketName 目标存储桶
* @param srcObjectName 目标文件名
*/
public static ObjectWriteResponse copyFile(String bucketName, String objectName,
String srcBucketName, String srcObjectName) throws Exception {
return minioClient.copyObject(
CopyObjectArgs.builder()
.source(CopySource.builder().bucket(bucketName).object(objectName).build())
.bucket(srcBucketName)
.object(srcObjectName)
.build());
}
/**
* 删除文件
* @param bucketName 存储桶
* @param objectName 文件名称
*/
public static void removeFile(String bucketName, String objectName) throws Exception {
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build());
}
/**
* 批量删除文件
* @param bucketName 存储桶
* @param keys 需要删除的文件列表
* @return
*/
public static void removeFiles(String bucketName, List<String> keys) {
List<DeleteObject> objects = new LinkedList<>();
keys.forEach(s -> {
objects.add(new DeleteObject(s));
try {
removeFile(bucketName, s);
} catch (Exception e) {
log.error("批量删除失败error:{}",e);
}
});
}
/**
* 获取文件外链
* @param bucketName 存储桶
* @param objectName 文件名
* @param expires 过期时间 <=7 外链有效时间单位
* @return url
* @throws Exception
*/
public static String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
return minioClient.getPresignedObjectUrl(args);
}
/**
* 获得文件外链
* @param bucketName
* @param objectName
* @return url
* @throws Exception
*/
public static String getPresignedObjectUrl(String bucketName, String objectName) throws Exception {
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(objectName)
.method(Method.GET).build();
return minioClient.getPresignedObjectUrl(args);
}
/**
* 将URLDecoder编码转成UTF8
* @param str
* @return
* @throws UnsupportedEncodingException
*/
public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
return URLDecoder.decode(url, "UTF-8");
}
/****************************** Operate Files End ******************************/
}

View File

@ -0,0 +1,9 @@
package com.imooc.utils;
public class MyInfo {
public static String getMobile() {
return "";
}
}

View File

@ -0,0 +1,49 @@
package com.imooc.utils;
import java.util.List;
/**
*
* @Title: PagedGridResult.java
* @Package com.imooc.utils
* @Description: 用来返回分页Grid的数据格式
* Copyright: Copyright (c) 2021
*/
public class PagedGridResult {
private int page; // 当前页数
private long total; // 总页数
private long records; // 总记录数
private List<?> rows; // 每行显示的内容
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public void setTotal(int total) {
this.total = total;
}
public long getRecords() {
return records;
}
public void setRecords(long records) {
this.records = records;
}
public List<?> getRows() {
return rows;
}
public void setRows(List<?> rows) {
this.rows = rows;
}
}

View File

@ -0,0 +1,287 @@
package com.imooc.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @Title: Redis 工具类
* @author 风间影月
*/
@Component
public class RedisOperator {
@Autowired
private StringRedisTemplate redisTemplate;
// Key简单的key-value操作
/**
* 判断key是否存在
* @param key
* @return
*/
public boolean keyIsExist(String key) {
return redisTemplate.hasKey(key);
}
/**
* 实现命令TTL key以秒为单位返回给定 key的剩余生存时间(TTL, time to live)
*
* @param key
* @return
*/
public long ttl(String key) {
return redisTemplate.getExpire(key);
}
/**
* 实现命令expire 设置过期时间单位秒
*
* @param key
* @return
*/
public void expire(String key, long timeout) {
redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 实现命令increment key增加key一次
*
* @param key
* @return
*/
public long increment(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 累加使用hash
*/
public long incrementHash(String name, String key, long delta) {
return redisTemplate.opsForHash().increment(name, key, delta);
}
/**
* 累减使用hash
*/
public long decrementHash(String name, String key, long delta) {
delta = delta * (-1);
return redisTemplate.opsForHash().increment(name, key, delta);
}
/**
* hash 设置value
*/
public void setHashValue(String name, String key, String value) {
redisTemplate.opsForHash().put(name, key, value);
}
/**
* hash 获得value
*/
public String getHashValue(String name, String key) {
return (String)redisTemplate.opsForHash().get(name, key);
}
/**
* 实现命令decrement key减少key一次
*
* @param key
* @return
*/
public long decrement(String key, long delta) {
return redisTemplate.opsForValue().decrement(key, delta);
}
/**
* 实现命令KEYS pattern查找所有符合给定模式 pattern的 key
*/
public Set<String> keys(String pattern) {
return redisTemplate.keys(pattern);
}
/**
* 实现命令DEL key删除一个key
*
* @param key
*/
public void del(String key) {
redisTemplate.delete(key);
}
// String字符串
/**
* 实现命令SET key value设置一个key-value将字符串值 value关联到 key
*
* @param key
* @param value
*/
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 实现命令SET key value EX seconds设置key-value和超时时间
*
* @param key
* @param value
* @param timeout
* 以秒为单位
*/
public void set(String key, String value, long timeout) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 如果key不存在则设置如果存在则报错
* @param key
* @param value
*/
public void setnx60s(String key, String value) {
redisTemplate.opsForValue().setIfAbsent(key, value, 60, TimeUnit.SECONDS);
}
/**
* 如果key不存在则设置如果存在则报错
* @param key
* @param value
*/
public void setnx(String key, String value) {
redisTemplate.opsForValue().setIfAbsent(key, value);
}
/**
* 实现命令GET key返回 key所关联的字符串值
*
* @param key
* @return value
*/
public String get(String key) {
return (String)redisTemplate.opsForValue().get(key);
}
/**
* 批量查询对应mget
* @param keys
* @return
*/
public List<String> mget(List<String> keys) {
return redisTemplate.opsForValue().multiGet(keys);
}
/**
* 批量查询管道pipeline
* @param keys
* @return
*/
public List<Object> batchGet(List<String> keys) {
// nginx -> keepalive
// redis -> pipeline
List<Object> result = redisTemplate.executePipelined(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
StringRedisConnection src = (StringRedisConnection)connection;
for (String k : keys) {
src.get(k);
}
return null;
}
});
return result;
}
// Hash哈希表
/**
* 实现命令HSET key field value将哈希表 key中的域 field的值设为 value
*
* @param key
* @param field
* @param value
*/
public void hset(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* 实现命令HGET key field返回哈希表 key中给定域 field的值
*
* @param key
* @param field
* @return
*/
public String hget(String key, String field) {
return (String) redisTemplate.opsForHash().get(key, field);
}
/**
* 实现命令HDEL key field [field ...]删除哈希表 key 中的一个或多个指定域不存在的域将被忽略
*
* @param key
* @param fields
*/
public void hdel(String key, Object... fields) {
redisTemplate.opsForHash().delete(key, fields);
}
/**
* 实现命令HGETALL key返回哈希表 key中所有的域和值
*
* @param key
* @return
*/
public Map<Object, Object> hgetall(String key) {
return redisTemplate.opsForHash().entries(key);
}
// List列表
/**
* 实现命令LPUSH key value将一个值 value插入到列表 key的表头
*
* @param key
* @param value
* @return 执行 LPUSH命令后列表的长度
*/
public long lpush(String key, String value) {
return redisTemplate.opsForList().leftPush(key, value);
}
/**
* 实现命令LPOP key移除并返回列表 key的头元素
*
* @param key
* @return 列表key的头元素
*/
public String lpop(String key) {
return (String)redisTemplate.opsForList().leftPop(key);
}
/**
* 实现命令RPUSH key value将一个值 value插入到列表 key的表尾(最右边)
*
* @param key
* @param value
* @return 执行 LPUSH命令后列表的长度
*/
public long rpush(String key, String value) {
return redisTemplate.opsForList().rightPush(key, value);
}
}

View File

@ -0,0 +1,74 @@
package com.imooc.utils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SMSUtils {
@Autowired
private TencentCloudProperties tencentCloudProperties;
public void sendSMS(String phone, String code) throws Exception {
try {
/* 必要步骤
* 实例化一个认证对象入参需要传入腾讯云账户密钥对secretIdsecretKey
* 这里采用的是从环境变量读取的方式需要在环境变量中先设置这两个值
* 你也可以直接在代码中写死密钥对但是小心不要将代码复制上传或者分享给他人
* 以免泄露密钥对危及你的财产安全
* CAM密匙查询获取: https://console.cloud.tencent.com/cam/capi*/
Credential cred = new Credential(tencentCloudProperties.getSecretId(),
tencentCloudProperties.getSecretKey());
// 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
// httpProfile.setReqMethod("POST"); // 默认使用POST
/* SDK会自动指定域名通常是不需要特地指定域名的但是如果你访问的是金融区的服务
* 则必须手动指定域名例如sms的上海金融区域名 sms.ap-shanghai-fsi.tencentcloudapi.com */
httpProfile.setEndpoint("sms.tencentcloudapi.com");
// 实例化一个client选项
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
SmsClient client = new SmsClient(cred, "ap-nanjing", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
SendSmsRequest req = new SendSmsRequest();
String[] phoneNumberSet1 = {"+86" + phone};//电话号码
req.setPhoneNumberSet(phoneNumberSet1);
req.setSmsSdkAppId("1400966042"); // 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId
req.setSignName("无终街科技"); // 签名
req.setTemplateId("2375314"); // 模板id必须填写已审核通过的模板 ID模板ID可登录 [短信控制台] 查看
/* 模板参数(自定义占位变量): 若无模板参数,则设置为空 */
String[] templateParamSet1 = {code};
req.setTemplateParamSet(templateParamSet1);
// 返回的resp是一个SendSmsResponse的实例与请求对象对应
SendSmsResponse resp = client.SendSms(req);
// 输出json格式的字符串回包
// System.out.println(SendSmsResponse.toJsonString(resp));
} catch (TencentCloudSDKException e) {
System.out.println(e.toString());
}
}
public static void main(String[] args) {
try {
new SMSUtils().sendSMS("15237439161", "7896");
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,23 @@
package com.imooc.utils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author vercen
* @version 1.0
* @date 2023/5/25 10:21
* 获取短信配置
*/
@Component
@Data
@PropertySource("classpath:tencentcloud.properties")
@ConfigurationProperties(prefix = "tencent.cloud")
public class TencentCloudProperties {
private String secretId;
private String secretKey;
}

View File

@ -0,0 +1,35 @@
package org.n3r.idworker;
import org.n3r.idworker.strategy.DefaultRandomCodeStrategy;
public class Code {
private static RandomCodeStrategy strategy;
static {
RandomCodeStrategy strategy = new DefaultRandomCodeStrategy();
strategy.init();
configure(strategy);
}
public static synchronized void configure(RandomCodeStrategy custom) {
if (strategy == custom) return;
if (strategy != null) strategy.release();
strategy = custom;
}
/**
* Next Unique code.
* The max length will be 1024-Integer.MAX-Integer.MAX(2147483647) which has 4+10+10+2*1=26 characters.
* The min length will be 0-0.
*
* @return unique string code.
*/
public static synchronized String next() {
long workerId = Id.getWorkerId();
int prefix = strategy.prefix();
int next = strategy.next();
return String.format("%d-%03d-%06d", workerId, prefix, next);
}
}

View File

@ -0,0 +1,19 @@
package org.n3r.idworker;
import org.n3r.idworker.strategy.DayPrefixRandomCodeStrategy;
public class DayCode {
static RandomCodeStrategy strategy;
static {
DayPrefixRandomCodeStrategy dayPrefixCodeStrategy = new DayPrefixRandomCodeStrategy("yyMM");
dayPrefixCodeStrategy.setMinRandomSize(7);
dayPrefixCodeStrategy.setMaxRandomSize(7);
strategy = dayPrefixCodeStrategy;
strategy.init();
}
public static synchronized String next() {
return String.format("%d-%04d-%07d", Id.getWorkerId(), strategy.prefix(), strategy.next());
}
}

View File

@ -0,0 +1,29 @@
package org.n3r.idworker;
import org.n3r.idworker.strategy.DefaultWorkerIdStrategy;
public class Id {
private static WorkerIdStrategy workerIdStrategy;
private static IdWorker idWorker;
static {
configure(DefaultWorkerIdStrategy.instance);
}
public static synchronized void configure(WorkerIdStrategy custom) {
if (workerIdStrategy == custom) return;
if (workerIdStrategy != null) workerIdStrategy.release();
workerIdStrategy = custom;
workerIdStrategy.initialize();
idWorker = new IdWorker(workerIdStrategy.availableWorkerId());
}
public static long next() {
return idWorker.nextId();
}
public static long getWorkerId() {
return idWorker.getWorkerId();
}
}

View File

@ -0,0 +1,91 @@
package org.n3r.idworker;
import java.security.SecureRandom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IdWorker {
protected long epoch = 1288834974657L;
// protected long epoch = 1387886498127L; // 2013-12-24 20:01:38.127
protected long workerIdBits = 10L;
protected long maxWorkerId = -1L ^ (-1L << workerIdBits);
protected long sequenceBits = 11L;
protected long workerIdShift = sequenceBits;
protected long timestampLeftShift = sequenceBits + workerIdBits;
protected long sequenceMask = -1L ^ (-1L << sequenceBits);
protected long lastMillis = -1L;
protected final long workerId;
protected long sequence = 0L;
protected Logger logger = LoggerFactory.getLogger(IdWorker.class);
public IdWorker(long workerId) {
this.workerId = checkWorkerId(workerId);
logger.debug("worker starting. timestamp left shift {}, worker id {}", timestampLeftShift, workerId);
}
public long getEpoch() {
return epoch;
}
private long checkWorkerId(long workerId) {
// sanity check for workerId
if (workerId > maxWorkerId || workerId < 0) {
int rand = new SecureRandom().nextInt((int) maxWorkerId + 1);
logger.warn("worker Id can't be greater than {} or less than 0, use a random {}", maxWorkerId, rand);
return rand;
}
return workerId;
}
public synchronized long nextId() {
long timestamp = millisGen();
if (timestamp < lastMillis) {
logger.error("clock is moving backwards. Rejecting requests until {}.", lastMillis);
throw new InvalidSystemClock(String.format(
"Clock moved backwards. Refusing to generate id for {} milliseconds", lastMillis - timestamp));
}
if (lastMillis == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0)
timestamp = tilNextMillis(lastMillis);
} else {
sequence = 0;
}
lastMillis = timestamp;
long diff = timestamp - getEpoch();
return (diff << timestampLeftShift) |
(workerId << workerIdShift) |
sequence;
}
protected long tilNextMillis(long lastMillis) {
long millis = millisGen();
while (millis <= lastMillis)
millis = millisGen();
return millis;
}
protected long millisGen() {
return System.currentTimeMillis();
}
public long getLastMillis() {
return lastMillis;
}
public long getWorkerId() {
return workerId;
}
}

View File

@ -0,0 +1,7 @@
package org.n3r.idworker;
public class InvalidSystemClock extends RuntimeException {
public InvalidSystemClock(String message) {
super(message);
}
}

View File

@ -0,0 +1,11 @@
package org.n3r.idworker;
public interface RandomCodeStrategy {
void init();
int prefix();
int next();
void release();
}

View File

@ -0,0 +1,64 @@
package org.n3r.idworker;
import org.n3r.idworker.strategy.DefaultWorkerIdStrategy;
import org.n3r.idworker.utils.Utils;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class Sid {
private static WorkerIdStrategy workerIdStrategy;
private static IdWorker idWorker;
static {
configure(DefaultWorkerIdStrategy.instance);
}
public static synchronized void configure(WorkerIdStrategy custom) {
if (workerIdStrategy != null) {
workerIdStrategy.release();
}
workerIdStrategy = custom;
idWorker = new IdWorker(workerIdStrategy.availableWorkerId()) {
@Override
public long getEpoch() {
return Utils.midnightMillis();
}
};
}
/**
* 一天最大毫秒86400000最大占用27比特
* 27+10+11=48位 最大值281474976710655(15字)YK0XXHZ827(10字)
* 6位(YYMMDD)+15位共21位
*
* @return 固定21位数字字符串
*/
public static String next() {
long id = idWorker.nextId();
String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date());
return yyMMdd + String.format("%014d", id);
}
/**
* 返回固定16位的字母数字混编的字符串
*/
public String nextShort() {
long id = idWorker.nextId();
String yyMMdd = new SimpleDateFormat("yyMMdd").format(new Date());
return yyMMdd + Utils.padLeft(Utils.encode(id), 10, '0');
}
public static void main(String[] args) {
String aa = new Sid().nextShort();
String bb = new Sid().next();
System.out.println(aa);
System.out.println(bb);
}
}

View File

@ -0,0 +1,12 @@
package org.n3r.idworker;
public class Test {
public static void main(String[] args) {
for (int i = 0 ; i < 1000 ; i ++) {
// System.out.println(Sid.nextShort());
}
}
}

View File

@ -0,0 +1,9 @@
package org.n3r.idworker;
public interface WorkerIdStrategy {
void initialize();
long availableWorkerId();
void release();
}

View File

@ -0,0 +1,41 @@
package org.n3r.idworker.strategy;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DayPrefixRandomCodeStrategy extends DefaultRandomCodeStrategy {
private final String dayFormat;
private String lastDay;
public DayPrefixRandomCodeStrategy(String dayFormat) {
this.dayFormat = dayFormat;
}
@Override
public void init() {
String day = createDate();
if (day.equals(lastDay))
throw new RuntimeException("init failed for day unrolled");
lastDay = day;
availableCodes.clear();
release();
prefixIndex = Integer.parseInt(lastDay);
if (tryUsePrefix()) return;
throw new RuntimeException("prefix is not available " + prefixIndex);
}
private String createDate() {
return new SimpleDateFormat(dayFormat).format(new Date());
}
@Override
public int next() {
if (!lastDay.equals(createDate())) init();
return super.next();
}
}

View File

@ -0,0 +1,197 @@
package org.n3r.idworker.strategy;
import org.n3r.idworker.Id;
import org.n3r.idworker.RandomCodeStrategy;
import org.n3r.idworker.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayDeque;
import java.util.BitSet;
import java.util.Queue;
public class DefaultRandomCodeStrategy implements RandomCodeStrategy {
public static final int MAX_BITS = 1000000;
Logger log = LoggerFactory.getLogger(DefaultRandomCodeStrategy.class);
File idWorkerHome = Utils.createIdWorkerHome();
volatile FileLock fileLock;
BitSet codesFilter;
int prefixIndex = -1;
File codePrefixIndex;
int minRandomSize = 6;
int maxRandomSize = 6;
public DefaultRandomCodeStrategy() {
destroyFileLockWhenShutdown();
}
@Override
public void init() {
release();
while (++prefixIndex < 1000) {
if (tryUsePrefix()) return;
}
throw new RuntimeException("all prefixes are used up, the world maybe ends!");
}
public DefaultRandomCodeStrategy setMinRandomSize(int minRandomSize) {
this.minRandomSize = minRandomSize;
return this;
}
public DefaultRandomCodeStrategy setMaxRandomSize(int maxRandomSize) {
this.maxRandomSize = maxRandomSize;
return this;
}
protected boolean tryUsePrefix() {
codePrefixIndex = new File(idWorkerHome, Id.getWorkerId() + ".code.prefix." + prefixIndex);
if (!createPrefixIndexFile()) return false;
if (!createFileLock()) return false;
if (!createBloomFilter()) return false;
log.info("get available prefix index file {}", codePrefixIndex);
return true;
}
private boolean createFileLock() {
if (fileLock != null) fileLock.destroy();
fileLock = new FileLock(codePrefixIndex);
return fileLock.tryLock();
}
private boolean createBloomFilter() {
codesFilter = fileLock.readObject();
if (codesFilter == null) {
log.info("create new bloom filter");
codesFilter = new BitSet(MAX_BITS); // 2^24
} else {
int size = codesFilter.cardinality();
if (size >= MAX_BITS) {
log.warn("bloom filter with prefix file {} is already full", codePrefixIndex);
return false;
}
log.info("recreate bloom filter with cardinality {}", size);
}
return true;
}
private void destroyFileLockWhenShutdown() {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
release();
}
});
}
private boolean createPrefixIndexFile() {
try {
codePrefixIndex.createNewFile();
return codePrefixIndex.exists();
} catch (IOException e) {
e.printStackTrace();
log.warn("create file {} error {}", codePrefixIndex, e.getMessage());
}
return false;
}
@Override
public int prefix() {
return prefixIndex;
}
static final int CACHE_CODES_NUM = 1000;
SecureRandom secureRandom = new SecureRandom();
Queue<Integer> availableCodes = new ArrayDeque<Integer>(CACHE_CODES_NUM);
@Override
public int next() {
if (availableCodes.isEmpty()) generate();
return availableCodes.poll();
}
@Override
public synchronized void release() {
if (fileLock != null) {
fileLock.writeObject(codesFilter);
fileLock.destroy();
fileLock = null;
}
}
private void generate() {
for (int i = 0; i < CACHE_CODES_NUM; ++i)
availableCodes.add(generateOne());
fileLock.writeObject(codesFilter);
}
private int generateOne() {
while (true) {
int code = secureRandom.nextInt(max(maxRandomSize));
boolean existed = contains(code);
code = !existed ? add(code) : tryFindAvailableCode(code);
if (code >= 0) return code;
init();
}
}
private int tryFindAvailableCode(int code) {
int next = codesFilter.nextClearBit(code);
if (next != -1 && next < max(maxRandomSize)) return add(next);
next = codesFilter.previousClearBit(code);
if (next != -1) return add(next);
return -1;
}
private int add(int code) {
codesFilter.set(code);
return code;
}
private boolean contains(int code) {
return codesFilter.get(code);
}
private int max(int size) {
switch (size) {
case 1: // fall through
case 2: // fall through
case 3: // fall through
case 4:
return 10000;
case 5:
return 100000;
case 6:
return 1000000;
case 7:
return 10000000;
case 8:
return 100000000;
case 9:
return 1000000000;
default:
return Integer.MAX_VALUE;
}
}
}

View File

@ -0,0 +1,205 @@
package org.n3r.idworker.strategy;
import org.n3r.idworker.WorkerIdStrategy;
import org.n3r.idworker.utils.HttpReq;
import org.n3r.idworker.utils.Ip;
import org.n3r.idworker.utils.Props;
import org.n3r.idworker.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Properties;
import java.util.Random;
public class DefaultWorkerIdStrategy implements WorkerIdStrategy {
static long workerIdBits = 10L;
static long maxWorkerId = -1L ^ (-1L << workerIdBits);
static Random random = new SecureRandom();
public static final WorkerIdStrategy instance = new DefaultWorkerIdStrategy();
private final Properties props =
Props.tryProperties("idworker-client.properties", Utils.DOT_IDWORKERS);
private final String idWorkerServerUrl =
props.getProperty("server.address", "http://id.worker.server:18001");
String userName = System.getProperty("user.name");
String ipDotUsername = Ip.ip + "." + userName;
String ipudotlock = ipDotUsername + ".lock.";
int workerIdIndex = ipudotlock.length();
long workerId;
FileLock fileLock;
Logger logger = LoggerFactory.getLogger(DefaultWorkerIdStrategy.class);
private boolean inited;
private void init() {
workerId = findAvailWorkerId();
if (workerId >= 0) {
destroyFileLockWhenShutdown();
startSyncThread();
} else {
syncWithWorkerIdServer();
workerId = findAvailWorkerId();
if (workerId < 0) workerId = increaseWithWorkerIdServer();
}
if (workerId < 0) workerId = tryToCreateOnIp();
if (workerId < 0) {
logger.warn("DANGEROUS!!! Try to use random worker id.");
workerId = tryToRandomOnIp(); // Try avoiding! it could cause duplicated
}
if (workerId < 0) {
logger.warn("the world may be ended!");
throw new RuntimeException("the world may be ended");
}
}
private void destroyFileLockWhenShutdown() {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
fileLock.destroy();
}
});
}
private void startSyncThread() {
new Thread() {
@Override
public void run() {
syncWithWorkerIdServer();
}
}.start();
}
private long increaseWithWorkerIdServer() {
String incId = HttpReq.get(idWorkerServerUrl)
.req("/inc")
.param("ipu", ipDotUsername)
.exec();
if (incId == null || incId.trim().isEmpty()) return -1L;
long lid = Long.parseLong(incId);
return checkAvail(lid);
}
private long tryToCreateOnIp() {
long wid = Ip.lip & maxWorkerId;
return checkAvail(wid);
}
private long tryToRandomOnIp() {
long avaiWorkerId = -1L;
long tryTimes = -1;
while (avaiWorkerId < 0 && ++tryTimes < maxWorkerId) {
long wid = Ip.lip & random.nextInt((int) maxWorkerId);
avaiWorkerId = checkAvail(wid);
}
return avaiWorkerId;
}
private long checkAvail(long wid) {
long availWorkerId = -1L;
try {
File idWorkerHome = Utils.createIdWorkerHome();
new File(idWorkerHome, ipudotlock + String.format("%04d", wid)).createNewFile();
availWorkerId = findAvailWorkerId();
} catch (IOException e) {
logger.warn("checkAvail error", e);
}
return availWorkerId;
}
private void syncWithWorkerIdServer() {
String syncIds = HttpReq.get(idWorkerServerUrl).req("/sync")
.param("ipu", ipDotUsername).param("ids", buildWorkerIdsOfCurrentIp())
.exec();
if (syncIds == null || syncIds.trim().isEmpty()) return;
String[] syncIdsArr = syncIds.split(",");
File idWorkerHome = Utils.createIdWorkerHome();
for (String syncId : syncIdsArr) {
try {
new File(idWorkerHome, ipudotlock + syncId).createNewFile();
} catch (IOException e) {
logger.warn("create workerid lock file error", e);
}
}
}
private String buildWorkerIdsOfCurrentIp() {
StringBuilder sb = new StringBuilder();
File idWorkerHome = Utils.createIdWorkerHome();
for (File lockFile : idWorkerHome.listFiles()) {
// check the format like 10.142.1.151.lock.0001
if (!lockFile.getName().startsWith(ipudotlock)) continue;
String workerId = lockFile.getName().substring(workerIdIndex);
if (!workerId.matches("\\d\\d\\d\\d")) continue;
if (sb.length() > 0) sb.append(',');
sb.append(workerId);
}
return sb.toString();
}
/**
* Find the local available worker id.
*
* @return -1 when N/A
*/
private long findAvailWorkerId() {
File idWorkerHome = Utils.createIdWorkerHome();
for (File lockFile : idWorkerHome.listFiles()) {
// check the format like 10.142.1.151.lock.0001
if (!lockFile.getName().startsWith(ipudotlock)) continue;
String workerId = lockFile.getName().substring(workerIdIndex);
if (!workerId.matches("\\d\\d\\d\\d")) continue;
FileLock fileLock = new FileLock(lockFile);
if (!fileLock.tryLock()) {
fileLock.destroy();
continue;
}
this.fileLock = fileLock;
return Long.parseLong(workerId);
}
return -1;
}
@Override
public void initialize() {
if (inited) return;
init();
this.inited = true;
}
@Override
public long availableWorkerId() {
return workerId;
}
@Override
public void release() {
if (fileLock != null) fileLock.destroy();
inited = false;
}
}

View File

@ -0,0 +1,132 @@
package org.n3r.idworker.strategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.channels.Channels;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.OverlappingFileLockException;
/**
* A file lock a la flock/funlock
* <p/>
* The given path will be created and opened if it doesn't exist.
*/
public class FileLock {
private final File file;
private FileChannel channel;
private java.nio.channels.FileLock flock = null;
Logger logger = LoggerFactory.getLogger(FileLock.class);
public FileLock(File file) {
this.file = file;
try {
file.createNewFile(); // create the file if it doesn't exist
channel = new RandomAccessFile(file, "rw").getChannel();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Lock the file or throw an exception if the lock is already held
*/
public void lock() {
try {
synchronized (this) {
logger.trace("Acquiring lock on {}", file.getAbsolutePath());
flock = channel.lock();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Try to lock the file and return true if the locking succeeds
*/
public boolean tryLock() {
synchronized (this) {
logger.trace("Acquiring lock on {}", file.getAbsolutePath());
try {
// weirdly this method will return null if the lock is held by another
// process, but will throw an exception if the lock is held by this process
// so we have to handle both cases
flock = channel.tryLock();
return flock != null;
} catch (OverlappingFileLockException e) {
return false;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* Unlock the lock if it is held
*/
public void unlock() {
synchronized (this) {
logger.trace("Releasing lock on {}", file.getAbsolutePath());
if (flock == null) return;
try {
flock.release();
} catch (ClosedChannelException e) {
// Ignore
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* Destroy this lock, closing the associated FileChannel
*/
public void destroy() {
synchronized (this) {
unlock();
if (!channel.isOpen()) return;
try {
channel.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("unchecked")
public <T> T readObject() {
try {
InputStream is = Channels.newInputStream(channel);
ObjectInputStream objectReader = new ObjectInputStream(is);
return (T) objectReader.readObject();
} catch (EOFException e) {
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
public synchronized boolean writeObject(Object object) {
if (!channel.isOpen()) return false;
try {
channel.position(0);
OutputStream out = Channels.newOutputStream(channel);
ObjectOutputStream objectOutput = new ObjectOutputStream(out);
objectOutput.writeObject(object);
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,113 @@
package org.n3r.idworker.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.*;
public class HttpReq {
private final String baseUrl;
private String req;
private StringBuilder params = new StringBuilder();
Logger logger = LoggerFactory.getLogger(HttpReq.class);
public HttpReq(String baseUrl) {
this.baseUrl = baseUrl;
}
public static HttpReq get(String baseUrl) {
return new HttpReq(baseUrl);
}
public HttpReq req(String req) {
this.req = req;
return this;
}
public HttpReq param(String name, String value) {
if (params.length() > 0) params.append('&');
try {
params.append(name).append('=').append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return this;
}
public String exec() {
HttpURLConnection http = null;
try {
http = (HttpURLConnection) new URL(baseUrl
+ (req == null ? "" : req)
+ (params.length() > 0 ? ("?" + params) : "")).openConnection();
http.setRequestProperty("Accept-Charset", "UTF-8");
HttpURLConnection.setFollowRedirects(false);
http.setConnectTimeout(5 * 1000);
http.setReadTimeout(5 * 1000);
http.connect();
int status = http.getResponseCode();
String charset = getCharset(http.getHeaderField("Content-Type"));
if (status == 200) {
return readResponseBody(http, charset);
} else {
logger.warn("non 200 respoonse :" + readErrorResponseBody(http, status, charset));
return null;
}
} catch (Exception e) {
logger.error("exec error {}", e.getMessage());
return null;
} finally {
if (http != null) http.disconnect();
}
}
private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) throws IOException {
InputStream errorStream = http.getErrorStream();
if (errorStream != null) {
String error = toString(charset, errorStream);
return ("STATUS CODE =" + status + "\n\n" + error);
} else {
return ("STATUS CODE =" + status);
}
}
private static String readResponseBody(HttpURLConnection http, String charset) throws IOException {
InputStream inputStream = http.getInputStream();
return toString(charset, inputStream);
}
private static String toString(String charset, InputStream inputStream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return new String(baos.toByteArray(), charset);
}
private static String getCharset(String contentType) {
if (contentType == null) return "UTF-8";
String charset = null;
for (String param : contentType.replace(" ", "").split(";")) {
if (param.startsWith("charset=")) {
charset = param.split("=", 2)[1];
break;
}
}
return charset == null ? "UTF-8" : charset;
}
}

View File

@ -0,0 +1,60 @@
package org.n3r.idworker.utils;
/**
* This utility provides methods to either convert an IPv4 address to its long format or a 32bit dotted format.
*
* @author Aion
* Created on 22/11/12
*/
public class IPv4Utils {
/**
* Returns the long format of the provided IP address.
*
* @param ipAddress the IP address
* @return the long format of <code>ipAddress</code>
* @throws IllegalArgumentException if <code>ipAddress</code> is invalid
*/
public static long toLong(String ipAddress) {
if (ipAddress == null || ipAddress.isEmpty()) {
throw new IllegalArgumentException("ip address cannot be null or empty");
}
String[] octets = ipAddress.split(java.util.regex.Pattern.quote("."));
if (octets.length != 4) {
throw new IllegalArgumentException("invalid ip address");
}
long ip = 0;
for (int i = 3; i >= 0; i--) {
long octet = Long.parseLong(octets[3 - i]);
if (octet > 255 || octet < 0) {
throw new IllegalArgumentException("invalid ip address");
}
ip |= octet << (i * 8);
}
return ip;
}
/**
* Returns the 32bit dotted format of the provided long ip.
*
* @param ip the long ip
* @return the 32bit dotted format of <code>ip</code>
* @throws IllegalArgumentException if <code>ip</code> is invalid
*/
public static String toString(long ip) {
// if ip is bigger than 255.255.255.255 or smaller than 0.0.0.0
if (ip > 4294967295l || ip < 0) {
throw new IllegalArgumentException("invalid ip");
}
StringBuilder ipAddress = new StringBuilder();
for (int i = 3; i >= 0; i--) {
int shift = i * 8;
ipAddress.append((ip & (0xff << shift)) >> shift);
if (i > 0) {
ipAddress.append(".");
}
}
return ipAddress.toString();
}
}

View File

@ -0,0 +1,50 @@
package org.n3r.idworker.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
public class Ip {
static Logger logger = LoggerFactory.getLogger(Ip.class);
public static String ip;
public static long lip;
static {
try {
InetAddress localHostLANAddress = getFirstNonLoopbackAddress();
ip = localHostLANAddress.getHostAddress();
byte[] address = localHostLANAddress.getAddress();
lip = ((address [0] & 0xFFL) << (3*8)) +
((address [1] & 0xFFL) << (2*8)) +
((address [2] & 0xFFL) << (1*8)) +
(address [3] & 0xFFL);
} catch (Exception e) {
logger.error("get ipv4 failed ", e);
}
}
private static InetAddress getFirstNonLoopbackAddress() throws SocketException {
Enumeration en = NetworkInterface.getNetworkInterfaces();
while (en.hasMoreElements()) {
NetworkInterface i = (NetworkInterface) en.nextElement();
for (Enumeration en2 = i.getInetAddresses(); en2.hasMoreElements(); ) {
InetAddress addr = (InetAddress) en2.nextElement();
if (addr.isLoopbackAddress()) continue;
if (addr instanceof Inet4Address) {
return addr;
}
}
}
return null;
}
}

View File

@ -0,0 +1,70 @@
package org.n3r.idworker.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Properties;
import static java.io.File.separator;
import static org.n3r.idworker.utils.Serializes.closeQuietly;
public class Props {
static Logger log = LoggerFactory.getLogger(Props.class);
public static Properties tryProperties(String propertiesFileName, String userHomeBasePath) {
Properties properties = new Properties();
InputStream is = null;
try {
is = Props.tryResource(propertiesFileName, userHomeBasePath, Silent.ON);
if (is != null) properties.load(is);
} catch (IOException e) {
log.error("load properties error: {}", e.getMessage());
} finally {
closeQuietly(is);
}
return properties;
}
enum Silent {ON, OFF}
public static InputStream tryResource(String propertiesFileName, String userHomeBasePath, Silent silent) {
InputStream is = currentDirResource(new File(propertiesFileName));
if (is != null) return is;
is = userHomeResource(propertiesFileName, userHomeBasePath);
if (is != null) return is;
is = classpathResource(propertiesFileName);
if (is != null || silent == Silent.ON) return is;
throw new RuntimeException("fail to find " + propertiesFileName + " in current dir or classpath");
}
private static InputStream userHomeResource(String pathname, String appHome) {
String filePath = System.getProperty("user.home") + separator + appHome;
File dir = new File(filePath);
if (!dir.exists()) return null;
return currentDirResource(new File(dir, pathname));
}
private static InputStream currentDirResource(File file) {
if (!file.exists()) return null;
try {
return new FileInputStream(file);
} catch (FileNotFoundException e) {
// This should not happened
log.error("read file {} error", file, e);
return null;
}
}
public static InputStream classpathResource(String resourceName) {
return Props.class.getClassLoader().getResourceAsStream(resourceName);
}
}

View File

@ -0,0 +1,118 @@
package org.n3r.idworker.utils;
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
public class Serializes {
@SuppressWarnings("unchecked")
public static <T> List<T> readObjects(File file) {
ArrayList<T> objects = new ArrayList<T>();
ObjectInputStream objectReader = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
objectReader = new ObjectInputStream(fis);
while (true)
objects.add((T) objectReader.readObject());
} catch (EOFException e) {
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
closeQuietly(objectReader);
closeQuietly(fis);
}
return objects;
}
@SuppressWarnings("unchecked")
public static <T> T readObject(File file) {
ObjectInputStream objectReader = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
objectReader = new ObjectInputStream(fis);
return (T) objectReader.readObject();
} catch (EOFException e) {
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
closeQuietly(objectReader);
closeQuietly(fis);
}
return null;
}
public static void writeObject(File file, Object object) {
ObjectOutputStream objectOutput = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
objectOutput = new ObjectOutputStream(fos);
objectOutput.writeObject(object);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
closeQuietly(objectOutput);
closeQuietly(fos);
}
}
public static void writeObject(FileOutputStream fos, Object object) {
FileChannel channel = fos.getChannel();
if (!channel.isOpen()) throw new RuntimeException("channel is closed");
try {
channel.position(0);
ObjectOutputStream objectOutput = new ObjectOutputStream(fos);
objectOutput.writeObject(object);
fos.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
}
}
public static void writeObjects(File file, Object... objects) {
ObjectOutputStream objectOutput = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
objectOutput = new ObjectOutputStream(fos);
for (Object object : objects)
objectOutput.writeObject(object);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
closeQuietly(objectOutput);
closeQuietly(fos);
}
}
public static void closeQuietly(OutputStream os) {
if (os != null) try {
os.close();
} catch (IOException e) {
// ignore
}
}
public static void closeQuietly(InputStream is) {
if (is != null) try {
is.close();
} catch (IOException e) {
// ignore
}
}
}

View File

@ -0,0 +1,114 @@
package org.n3r.idworker.utils;
import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class Utils {
public static final String DOT_IDWORKERS = ".idworkers";
public static ClassLoader getClassLoader() {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
return contextClassLoader != null ? contextClassLoader : Utils.class.getClassLoader();
}
public static InputStream classResourceToStream(String resourceName) {
return getClassLoader().getResourceAsStream(resourceName);
}
public static String firstLine(String classResourceName) {
InputStream inputStream = null;
try {
inputStream = classResourceToStream(classResourceName);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
return bufferedReader.readLine();
} catch (IOException e) {
return null;
} finally {
if (inputStream != null) try {
inputStream.close();
} catch (IOException e) {
// ignore
}
}
}
public static String checkNotEmpty(String param, String name) {
if (param == null || param.isEmpty())
throw new IllegalArgumentException(name + " is empty");
return param;
}
public static long midnightMillis() {
// today
Calendar date = Calendar.getInstance();
// reset hour, minutes, seconds and millis
date.set(Calendar.HOUR_OF_DAY, 0);
date.set(Calendar.MINUTE, 0);
date.set(Calendar.SECOND, 0);
date.set(Calendar.MILLISECOND, 0);
return date.getTimeInMillis();
}
public static void main(String[] args) {
// 2013-12-25 00:00:00.000
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Timestamp(midnightMillis())));
System.out.println(encode(281474976710655L));
}
public static long decode(String s, String symbols) {
final int B = symbols.length();
long num = 0;
for (char ch : s.toCharArray()) {
num *= B;
num += symbols.indexOf(ch);
}
return num;
}
public static String encode(long num) {
return encode(num, defaultRange);
}
public static String encode(long num, String symbols) {
final int B = symbols.length();
StringBuilder sb = new StringBuilder();
while (num != 0) {
sb.append(symbols.charAt((int) (num % B)));
num /= B;
}
return sb.reverse().toString();
}
// all un-clearly-recognized letters are skiped.
static String defaultRange = "0123456789ABCDFGHKMNPRSTWXYZ";
public static String padLeft(String str, int size, char padChar) {
if (str.length() >= size) return str;
StringBuilder s = new StringBuilder();
for (int i = size - str.length(); i > 0; --i) {
s.append(padChar);
}
s.append(str);
return s.toString();
}
public static File createIdWorkerHome() {
String userHome = System.getProperty("user.home");
File idWorkerHome = new File(userHome + File.separator + DOT_IDWORKERS);
idWorkerHome.mkdirs();
if (idWorkerHome.isDirectory()) return idWorkerHome;
throw new RuntimeException("failed to create .idworkers at user home");
}
}

View File

@ -0,0 +1,2 @@
tencent.cloud.secretId=AKIDvhEVWHm0xe5JGxOZXGitnRovlKcfRzIN
tencent.cloud.secretKey=qPhiTxA7oENFrCH5dvxiCQN4UdWAYgYA

29
book-mapper/pom.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imooc</groupId>
<artifactId>imooc-red-book-dev</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--数据层-->
<artifactId>book-mapper</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.imooc</groupId>
<artifactId>book-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package com.imooc.mapper;
import com.imooc.my.mapper.MyMapper;
import com.imooc.pojo.Comment;
import org.springframework.stereotype.Repository;
@Repository
public interface CommentMapper extends MyMapper<Comment> {
}

View File

@ -0,0 +1,15 @@
package com.imooc.mapper;
import com.imooc.vo.CommentVO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public interface CommentMapperCustom {
public List<CommentVO> getCommentList(@Param("paramMap") Map<String, Object> map);
}

View File

@ -0,0 +1,9 @@
package com.imooc.mapper;
import com.imooc.my.mapper.MyMapper;
import com.imooc.pojo.Fans;
import org.springframework.stereotype.Repository;
@Repository
public interface FansMapper extends MyMapper<Fans> {
}

View File

@ -0,0 +1,20 @@
package com.imooc.mapper;
import com.imooc.my.mapper.MyMapper;
import com.imooc.pojo.Fans;
import com.imooc.vo.FansVO;
import com.imooc.vo.VlogerVO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public interface FansMapperCustom extends MyMapper<Fans> {
public List<VlogerVO> queryMyFollows(@Param("paramMap") Map<String, Object> map);
public List<FansVO> queryMyFans(@Param("paramMap") Map<String, Object> map);
}

View File

@ -0,0 +1,9 @@
package com.imooc.mapper;
import com.imooc.my.mapper.MyMapper;
import com.imooc.pojo.MyLikedVlog;
import org.springframework.stereotype.Repository;
@Repository
public interface MyLikedVlogMapper extends MyMapper<MyLikedVlog> {
}

View File

@ -0,0 +1,9 @@
package com.imooc.mapper;
import com.imooc.my.mapper.MyMapper;
import com.imooc.pojo.Users;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UsersMapper extends MyMapper<Users> {
}

View File

@ -0,0 +1,10 @@
package com.imooc.mapper;
import com.imooc.my.mapper.MyMapper;
import com.imooc.pojo.Vlog;
import org.springframework.stereotype.Repository;
@Repository
public interface VlogMapper extends MyMapper<Vlog> {
}

View File

@ -0,0 +1,23 @@
package com.imooc.mapper;
import com.imooc.vo.IndexVlogVO;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public interface VlogMapperCustom {
public List<IndexVlogVO> getIndexVlogList(@Param("paramMap")Map<String, Object> map);
public List<IndexVlogVO> getVlogDetailById(@Param("paramMap")Map<String, Object> map);
public List<IndexVlogVO> getMyLikedVlogList(@Param("paramMap")Map<String, Object> map);
public List<IndexVlogVO> getMyFollowVlogList(@Param("paramMap")Map<String, Object> map);
public List<IndexVlogVO> getMyFriendVlogList(@Param("paramMap")Map<String, Object> map);
}

View File

@ -0,0 +1,34 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2016 abel533@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.imooc.my.mapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/**
* 继承自己的MyMapper
*/
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
}

View File

@ -0,0 +1,17 @@
package com.imooc.repository;
import com.imooc.mo.MessageMO;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface MessageRepository extends MongoRepository<MessageMO, String> {
// 通过实现Repository自定义条件查询
List<MessageMO> findAllByToUserIdEqualsOrderByCreateTimeDesc(String toUserId,
Pageable pageable);
// void deleteAllByFromUserIdAndToUserIdAndMsgType();
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.CommentMapper" >
<resultMap id="BaseResultMap" type="com.imooc.pojo.Comment" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="vloger_id" property="vlogerId" jdbcType="VARCHAR" />
<result column="father_comment_id" property="fatherCommentId" jdbcType="VARCHAR" />
<result column="vlog_id" property="vlogId" jdbcType="VARCHAR" />
<result column="comment_user_id" property="commentUserId" jdbcType="VARCHAR" />
<result column="content" property="content" jdbcType="VARCHAR" />
<result column="like_counts" property="likeCounts" jdbcType="INTEGER" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
</resultMap>
</mapper>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.CommentMapperCustom" >
<!--
FIXME
思考:阿里规范明确规定不能超过三表关联,这里达到了四张表
我们应该如何优化呢使得sql脚本查询表位三表或者两表查询
来实现呢又或者说我们能不能不使用数据库使用别的手段中间件mycat
-->
<select id="getCommentList" parameterType="map" resultType="com.imooc.vo.CommentVO">
SELECT
c.id as commentId,
c.vlog_id as vlogId,
u.id as vlogerId,
u.nickname as commentUserNickname,
u.face as commentUserFace,
c.father_comment_id as fatherCommentId,
c.comment_user_id as commentUserId,
c.content as content,
c.like_counts as likeCounts,
fu.nickname as replyedUserNickname,
c.create_time as createTime
FROM
`comment` as c
LEFT JOIN
users as u
ON
c.comment_user_id = u.id
LEFT JOIN
`comment` as fc
ON
c.father_comment_id = fc.id
LEFT JOIN
users as fu
ON
fc.comment_user_id = fu.id
WHERE
c.vlog_id = #{paramMap.vlogId}
ORDER BY
c.like_counts DESC,
c.create_time DESC
</select>
</mapper>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.FansMapper" >
<resultMap id="BaseResultMap" type="com.imooc.pojo.Fans" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="vloger_id" property="vlogerId" jdbcType="VARCHAR" />
<result column="fan_id" property="fanId" jdbcType="VARCHAR" />
<result column="is_fan_friend_of_mine" property="isFanFriendOfMine" jdbcType="INTEGER" />
</resultMap>
</mapper>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.FansMapperCustom" >
<select id="queryMyFollows" resultType="com.imooc.vo.VlogerVO" parameterType="map">
SELECT
u.id as vlogerId,
u.nickname as nickname,
u.face as face
FROM
fans f
LEFT JOIN
users u
ON
f.vloger_id = u.id
WHERE
f.fan_id = #{paramMap.myId}
ORDER BY
u.nickname
ASC
</select>
<select id="queryMyFans" resultType="com.imooc.vo.FansVO" parameterType="map">
SELECT
u.id as fanId,
u.nickname as nickname,
u.face as face
FROM
fans f
LEFT JOIN
users u
ON
f.fan_id = u.id
WHERE
f.vloger_id = #{paramMap.myId}
ORDER BY
u.nickname
ASC
</select>
</mapper>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.MyLikedVlogMapper" >
<resultMap id="BaseResultMap" type="com.imooc.pojo.MyLikedVlog" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="user_id" property="userId" jdbcType="VARCHAR" />
<result column="vlog_id" property="vlogId" jdbcType="VARCHAR" />
</resultMap>
</mapper>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.UsersMapper" >
<resultMap id="BaseResultMap" type="com.imooc.pojo.Users" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="nickname" property="nickname" jdbcType="VARCHAR" />
<result column="imooc_num" property="imoocNum" jdbcType="VARCHAR" />
<result column="face" property="face" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="INTEGER" />
<result column="birthday" property="birthday" jdbcType="DATE" />
<result column="country" property="country" jdbcType="VARCHAR" />
<result column="province" property="province" jdbcType="VARCHAR" />
<result column="city" property="city" jdbcType="VARCHAR" />
<result column="district" property="district" jdbcType="VARCHAR" />
<result column="description" property="description" jdbcType="VARCHAR" />
<result column="bg_img" property="bgImg" jdbcType="VARCHAR" />
<result column="can_imooc_num_be_updated" property="canImoocNumBeUpdated" jdbcType="INTEGER" />
<result column="created_time" property="createdTime" jdbcType="TIMESTAMP" />
<result column="updated_time" property="updatedTime" jdbcType="TIMESTAMP" />
</resultMap>
</mapper>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.VlogMapper" >
<resultMap id="BaseResultMap" type="com.imooc.pojo.Vlog" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="vloger_id" property="vlogerId" jdbcType="VARCHAR" />
<result column="url" property="url" jdbcType="VARCHAR" />
<result column="cover" property="cover" jdbcType="VARCHAR" />
<result column="title" property="title" jdbcType="VARCHAR" />
<result column="width" property="width" jdbcType="INTEGER" />
<result column="height" property="height" jdbcType="INTEGER" />
<result column="like_counts" property="likeCounts" jdbcType="INTEGER" />
<result column="comments_counts" property="commentsCounts" jdbcType="INTEGER" />
<result column="is_private" property="isPrivate" jdbcType="INTEGER" />
<result column="created_time" property="createdTime" jdbcType="TIMESTAMP" />
<result column="updated_time" property="updatedTime" jdbcType="TIMESTAMP" />
</resultMap>
</mapper>

View File

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imooc.mapper.VlogMapperCustom" >
<select id="getIndexVlogList" parameterType="map" resultType="com.imooc.vo.IndexVlogVO">
SELECT
v.id as vlogId,
v.vloger_id as vlogerId,
u.face as vlogerFace,
u.nickname as vlogerName,
v.title as content,
v.url as url,
v.cover as cover,
v.width as width,
v.height as height,
v.like_counts as likeCounts,
v.comments_counts as commentsCounts,
v.is_private as isPrivate
FROM
vlog v
LEFT JOIN
users u
ON
v.vloger_id = u.id
WHERE
v.is_private = 0
<if test="paramMap.search != null and paramMap.search != ''">
AND v.title like '%${paramMap.search}%'
</if>
ORDER BY
v.created_time
DESC
</select>
<select id="getVlogDetailById" parameterType="map" resultType="com.imooc.vo.IndexVlogVO">
SELECT
v.id as vlogId,
v.vloger_id as vlogerId,
u.face as vlogerFace,
u.nickname as vlogerName,
v.title as content,
v.url as url,
v.cover as cover,
v.width as width,
v.height as height,
v.like_counts as likeCounts,
v.comments_counts as commentsCounts,
v.is_private as isPrivate
FROM
vlog v
LEFT JOIN
users u
ON
v.vloger_id = u.id
WHERE
v.id = #{paramMap.vlogId}
</select>
<select id="getMyLikedVlogList" parameterType="map" resultType="com.imooc.vo.IndexVlogVO">
SELECT
v.id as vlogId,
v.vloger_id as vlogerId,
-- u.face as vlogerFace,
-- u.nickname as vlogerName,
v.title as content,
v.url as url,
v.cover as cover,
v.width as width,
v.height as height,
v.like_counts as likeCounts,
v.comments_counts as commentsCounts,
v.is_private as isPrivate
FROM
vlog v
LEFT JOIN
my_liked_vlog mlv
ON
v.id = mlv.vlog_id
LEFT JOIN
users u
ON
mlv.user_id = u.id
WHERE
u.id = #{paramMap.userId}
AND
v.is_private = 0
ORDER BY
v.created_time
DESC
</select>
<select id="getMyFollowVlogList" parameterType="map" resultType="com.imooc.vo.IndexVlogVO">
SELECT
v.id as vlogId,
v.vloger_id as vlogerId,
u.face as vlogerFace,
u.nickname as vlogerName,
v.title as content,
v.url as url,
v.cover as cover,
v.width as width,
v.height as height,
v.like_counts as likeCounts,
v.comments_counts as commentsCounts,
v.is_private as isPrivate
FROM
vlog v
LEFT JOIN
fans f
ON
v.vloger_id = f.vloger_id
LEFT JOIN
users u
ON
f.vloger_id = u.id
WHERE
v.is_private = 0
AND
f.fan_id = #{paramMap.myId}
ORDER BY
v.created_time
DESC
</select>
<select id="getMyFriendVlogList" parameterType="map" resultType="com.imooc.vo.IndexVlogVO">
SELECT
v.id as vlogId,
v.vloger_id as vlogerId,
u.face as vlogerFace,
u.nickname as vlogerName,
v.title as content,
v.url as url,
v.cover as cover,
v.width as width,
v.height as height,
v.like_counts as likeCounts,
v.comments_counts as commentsCounts,
v.is_private as isPrivate
FROM
vlog v
LEFT JOIN
fans f
ON
v.vloger_id = f.fan_id
LEFT JOIN
users u
ON
f.fan_id = u.id
WHERE
v.is_private = 0
AND
f.vloger_id = #{paramMap.myId}
AND
f.is_fan_friend_of_mine = 1
ORDER BY
v.created_time
DESC
</select>
</mapper>

63
book-model/pom.xml Normal file
View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.imooc</groupId>
<artifactId>imooc-red-book-dev</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>book-model</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.imooc</groupId>
<artifactId>book-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- hibernate 验证框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- mysql 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- 通用mapper逆向工具 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<!-- pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,32 @@
package com.imooc.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CommentBO {
@NotBlank(message = "留言信息不完整")
private String vlogerId;
@NotBlank(message = "留言信息不完整")
private String fatherCommentId;
@NotBlank(message = "留言信息不完整")
private String vlogId;
@NotBlank(message = "当前用户信息不正确,请尝试重新登录")
private String commentUserId;
@NotBlank(message = "评论内容不能为空")
@Length(max = 50, message = "评论内容长度不能超过50")
private String content;
}

View File

@ -0,0 +1,23 @@
package com.imooc.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class RegistLoginBO {
@NotBlank(message = "手机号不能为空")
@Length(min = 11, max = 11, message = "手机长度不正确")
private String mobile;
@NotBlank(message = "验证码不能为空")
private String smsCode;
}

View File

@ -0,0 +1,28 @@
package com.imooc.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UpdatedUserBO {
private String id;
private String nickname;
private String imoocNum;
private String face;
private Integer sex;
private Date birthday;
private String country;
private String province;
private String city;
private String district;
private String description;
private String bgImg;
private Integer canImoocNumBeUpdated;
}

View File

@ -0,0 +1,22 @@
package com.imooc.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class VlogBO {
private String id;
private String vlogerId;
private String url;
private String cover;
private String title;
private Integer width;
private Integer height;
private Integer likeCounts;
private Integer commentsCounts;
}

Some files were not shown because too many files have changed in this diff Show More