diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 474300f..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,14 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "npm" # See documentation for possible values - directory: "/frontend" # Location of package manifests - schedule: - interval: "daily" - allow: - - dependency-name: "*" - dependency-type: "production" diff --git a/.github/workflows/codiga.yml b/.github/workflows/codiga.yml new file mode 100644 index 0000000..19a2602 --- /dev/null +++ b/.github/workflows/codiga.yml @@ -0,0 +1,25 @@ +name: "codiga" +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] +jobs: + check-quality: + runs-on: ubuntu-latest + name: Codiga Check + steps: + - name: Check code meets quality standards + id: codiga + uses: codiga/github-action@master + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + codiga_api_token: ${{ secrets.CODIGA_API_TOKEN }} + min_quality_grade: 'WARNING' + min_quality_score: '50' + max_defects_rate: '0.2' + max_complex_functions_rate: '0.0001' + max_long_functions_rate: '0.0001' + project_name: 'github-action-example' + max_timeout_sec: '600' diff --git a/.github/workflows/elasticsearch.yml b/.github/workflows/elasticsearch.yml new file mode 100644 index 0000000..3792251 --- /dev/null +++ b/.github/workflows/elasticsearch.yml @@ -0,0 +1,73 @@ +# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: elasticsearch image + +on: + workflow_dispatch: + inputs: + version: + description: The version of the Docker image to use. + type: string + required: true + default: 1.0.0 + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: big_three/elasticsearch + USER_NAME: zhaoyiqing97 + CONTEXT: ops/build/elasticsearch + +jobs: + + docker: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install cosign + uses: sigstore/cosign-installer@v2.4.0 + + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v2 + with: + driver-opts: image=moby/buildkit:buildx-stable-1 + + - name: Log into registry ${{ env.REGISTRY }} + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ env.USER_NAME }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.USER_NAME }}/${{ env.IMAGE_NAME }} + flavor: | + latest=auto + tags: | + type=semver,pattern={{version}},value=1.0.0 + + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v3 + with: + context: ${{env.CONTEXT}} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Sign the published Docker image + env: + COSIGN_EXPERIMENTAL: 1 + run: cosign sign ${{ env.REGISTRY }}/${{ env.USER_NAME }}/${{ env.IMAGE_NAME }}:${{ steps.build-and-push.outputs.tags }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 19deafe..26cc5fc 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -27,7 +27,7 @@ jobs: strategy: matrix: - java-version: [8] + java-version: [ 8 ] steps: - name: Checkout repository @@ -43,7 +43,7 @@ jobs: - name: Build with Maven run: | mvn -v - mvn clean install --file backend/pom.xml + mvn clean install --file backend/pom.xml -DskipTests mkdir ${{env.CONTEXT}}/target/extracted java -Djarmode=layertools -jar ${{env.CONTEXT}}/target/*.jar extract --destination ${{env.CONTEXT}}/target/extracted diff --git a/.gitignore b/.gitignore index cc1e752..c569b15 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ *.lock # Package Files # -*.jar +target/*.jar *.war *.ear target/ diff --git a/README.md b/README.md index a3cb344..4a45239 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,22 @@ ## docker 部署 -### 部署 +### prod-部署 ```shell cd ops/docker/prod docker compose up -d ``` +### dev-部署 + +```shell +cd ops/docker/dev +build-backend.sh +build-frontend.sh +docker compose up -d +``` + ### 更新 ```shell diff --git a/backend/Dockerfile b/backend/Dockerfile index 0ad5c72..5c7fc3f 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,8 @@ FROM openjdk:8-jre-alpine + +RUN apk --update --no-cache add curl jq +HEALTHCHECK --start-period=20s CMD curl -s http://localhost:8080/backend/actuator/health | jq ".status" | grep UP || exit 1 + # settings timezone ENV TZ Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone @@ -7,7 +11,7 @@ RUN mkdir /logs && chown spring:spring /logs RUN mkdir /app && chown spring:spring /app USER spring:spring -WORKDIR app +WORKDIR /app COPY ./target/extracted/dependencies/ ./ COPY ./target/extracted/spring-boot-loader/ ./ COPY ./target/extracted/snapshot-dependencies/ ./ diff --git a/backend/pom.xml b/backend/pom.xml index c51c5fa..304892c 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -9,6 +9,8 @@ 1.0-SNAPSHOT + 2.2.0 + 8.0.28 org.springframework.boot @@ -17,6 +19,7 @@ + org.springframework.boot spring-boot-starter @@ -38,39 +41,62 @@ org.springframework.boot - spring-boot-starter-test - test + spring-boot-starter-security + org.springframework.boot spring-boot-starter-web + - com.baomidou - mybatis-plus-boot-starter - 3.5.1 - - - org.projectlombok - lombok - true + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${mybatis-verison} mysql mysql-connector-java runtime - 8.0.28 + ${mysql-connector-verison} + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + + org.projectlombok + lombok + true com.google.guava guava 31.1-jre - + + org.apache.commons + commons-lang3 + 3.12.0 + + org.springframework.boot - spring-boot-starter-security + spring-boot-starter-test + test + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + ${mybatis-verison} + test + + diff --git a/backend/src/main/java/generator/Application.java b/backend/src/main/java/generator/Application.java index bf2ece8..391acaf 100644 --- a/backend/src/main/java/generator/Application.java +++ b/backend/src/main/java/generator/Application.java @@ -3,15 +3,17 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; /** * @author zyq */ @SpringBootApplication @MapperScan("generator.mapper") +@EnableElasticsearchRepositories public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - System.out.println("三巨头,永无BUG!"); - } + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + System.out.println("三巨头,永无BUG!"); + } } diff --git a/backend/src/main/java/generator/config/BeanConfig.java b/backend/src/main/java/generator/config/BeanConfig.java new file mode 100644 index 0000000..a6dfda2 --- /dev/null +++ b/backend/src/main/java/generator/config/BeanConfig.java @@ -0,0 +1,61 @@ +package generator.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.DateSerializer; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import generator.constant.CommonConstant; + +/** + * BeanConfig. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-16 : base version. + */ +@Configuration +public class BeanConfig { + /** + * jackSon 的 ObjectMapper + * + * @return ObjectMapper + */ + @Bean + public ObjectMapper objectMapper() { + // 序列化设置 + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setTimeZone(TimeZone.getDefault()); + // 序列换成json时,将所有的long变成string + SimpleModule simpleModule = new SimpleModule(); + simpleModule.addSerializer(Long.class, ToStringSerializer.instance); + simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); + // 日期序列化设置 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat(CommonConstant.DATE_TIME_FORMATTER_STRING))); + objectMapper.registerModule(simpleModule).registerModule(javaTimeModule); + + return objectMapper; + } + + /** + * 国际化 + * + * @return 对象 + */ + @Bean + public ReloadableResourceBundleMessageSource messageSource() { + ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); + messageSource.setBasename("classpath:org/springframework/security/messages_zh_CN"); + return messageSource; + } +} diff --git a/backend/src/main/java/generator/config/ElasticsearchConfiguration.java b/backend/src/main/java/generator/config/ElasticsearchConfiguration.java new file mode 100644 index 0000000..5b17aa6 --- /dev/null +++ b/backend/src/main/java/generator/config/ElasticsearchConfiguration.java @@ -0,0 +1,26 @@ +package generator.config; + +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.context.annotation.Bean; +import org.springframework.data.elasticsearch.client.ClientConfiguration; +import org.springframework.data.elasticsearch.client.RestClients; +import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration; + +/** + * ElasticsearchConfiguration. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-18 : base version. + */ +public class ElasticsearchConfiguration extends AbstractElasticsearchConfiguration { + @Override + @Bean + public RestHighLevelClient elasticsearchClient() { + final ClientConfiguration clientConfiguration = ClientConfiguration.builder() + .connectedTo("localhost:9200") + .build(); + + return RestClients.create(clientConfiguration).rest(); + } +} diff --git a/backend/src/main/java/generator/config/ProjectSetting.java b/backend/src/main/java/generator/config/ProjectSetting.java index 44dbeff..bba5d0d 100644 --- a/backend/src/main/java/generator/config/ProjectSetting.java +++ b/backend/src/main/java/generator/config/ProjectSetting.java @@ -16,6 +16,8 @@ @ConfigurationProperties("big-three") @Data public class ProjectSetting { - /** 允许跨域的域名 */ - private String[] corsMappings; + /** + * 允许跨域的域名 + */ + private String[] corsMappings; } diff --git a/backend/src/main/java/generator/config/SpringSecurityHandler.java b/backend/src/main/java/generator/config/SpringSecurityHandler.java new file mode 100644 index 0000000..20feeaf --- /dev/null +++ b/backend/src/main/java/generator/config/SpringSecurityHandler.java @@ -0,0 +1,75 @@ +package generator.config; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import generator.constant.CommonConstant; +import generator.domain.common.CustomerUser; +import generator.domain.common.ResultData; +import generator.domain.vo.UserInVO; +import lombok.RequiredArgsConstructor; +import lombok.val; + +/** + * SpringSecurityHandler. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-17 : base version. + */ +@Component +@RequiredArgsConstructor +public class SpringSecurityHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler, AuthenticationEntryPoint { + private final ObjectMapper objectMapper; + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { + val principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + if (principal instanceof CustomerUser) { + val customerUser = (CustomerUser) principal; + response.setContentType(CommonConstant.RESPONSE_CONTENT_TYPE); + val result = ResultData.success(new UserInVO().from(customerUser.getUserInfo())); + try (PrintWriter out = response.getWriter()) { + out.write(objectMapper.writeValueAsString(result)); + out.flush(); + } + } + } + + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + response.setContentType(CommonConstant.RESPONSE_CONTENT_TYPE); + val result = new ResultData<>(); + result.setMsg(exception.getMessage()); + try (PrintWriter out = response.getWriter()) { + out.write(objectMapper.writeValueAsString(result)); + out.flush(); + } + } + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + response.setContentType(CommonConstant.RESPONSE_CONTENT_TYPE); + val result = new ResultData<>(); + try (PrintWriter out = response.getWriter()) { + out.write(objectMapper.writeValueAsString(result)); + out.flush(); + } + } +} diff --git a/backend/src/main/java/generator/config/WebMvcConfig.java b/backend/src/main/java/generator/config/WebMvcConfig.java new file mode 100644 index 0000000..cc21a5e --- /dev/null +++ b/backend/src/main/java/generator/config/WebMvcConfig.java @@ -0,0 +1,31 @@ +package generator.config; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +/** + * WebMvcConfig. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-15 : base version. + */ +@Configuration +public class WebMvcConfig { + + /** + * web 请求的转换器,自动识别配置的spring bean + * + * @param objectMapper objectMapper + * @return MappingJackson2HttpMessageConverter + */ + @Bean + public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); + jsonConverter.setObjectMapper(objectMapper); + return jsonConverter; + } +} diff --git a/backend/src/main/java/generator/config/WebSecurityConfig.java b/backend/src/main/java/generator/config/WebSecurityConfig.java index 8757073..a48c06f 100644 --- a/backend/src/main/java/generator/config/WebSecurityConfig.java +++ b/backend/src/main/java/generator/config/WebSecurityConfig.java @@ -2,11 +2,13 @@ import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -15,7 +17,6 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import generator.filter.BigThreeFilter; -import generator.service.impl.UserDetailsServiceImpl; import lombok.val; /** @@ -26,63 +27,83 @@ @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - private final BigThreeFilter bigThreeFilter; - - private final ProjectSetting projectSetting; - - public WebSecurityConfig(BigThreeFilter bigThreeFilter, ProjectSetting projectSetting) { - this.bigThreeFilter = bigThreeFilter; - this.projectSetting = projectSetting; - } - - /** 提供用户信息,这里没有从数据库查询用户信息,在内存中模拟 */ - @Override - public UserDetailsService userDetailsService() { - // 获取用户账号密码及权限信息 - return new UserDetailsServiceImpl(); - } - - /** 密码编码器:不加密 */ - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService()); - } - - /** 授权规则配置 */ - @Override - protected void configure(HttpSecurity http) throws Exception { - // 授权配置 - http.authorizeRequests() - // 登录路径放行 - .antMatchers("/login", "/list") - .permitAll() - .anyRequest() - .authenticated() - .and() - .formLogin() - // .loginPage("/loginHtml") - .loginProcessingUrl("/doLogin") - .successForwardUrl("/loginSuccess") - // .successHandler()//指定登录成功的处理逻辑类 - // .failureHandler()//指定登录失败的处理逻辑类 - .permitAll(); - - // 本地跨域 - if (projectSetting.getCorsMappings() != null) { - val corsConf = new CorsConfiguration(); - corsConf.setAllowedOrigins(Lists.newArrayList(projectSetting.getCorsMappings())); - corsConf.setAllowedMethods(Lists.newArrayList("*")); - val source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", corsConf); - http.cors().configurationSource(source); + private final BigThreeFilter bigThreeFilter; + + private final ProjectSetting projectSetting; + + private final UserDetailsService userDetailsService; + + private final SpringSecurityHandler springSecurityHandler; + + public WebSecurityConfig(BigThreeFilter bigThreeFilter, ProjectSetting projectSetting, @Qualifier("UserDetailsServiceImpl") UserDetailsService userDetailsService, SpringSecurityHandler springSecurityHandler) { + this.bigThreeFilter = bigThreeFilter; + this.projectSetting = projectSetting; + this.userDetailsService = userDetailsService; + this.springSecurityHandler = springSecurityHandler; } - // 时间过滤器 - http.addFilterAfter(bigThreeFilter, SecurityContextPersistenceFilter.class); - } + /** + * 提供用户信息,这里没有从数据库查询用户信息,在内存中模拟 + */ + @Override + public UserDetailsService userDetailsService() { + // 获取用户账号密码及权限信息 + return userDetailsService; + } + + /** + * 密码编码器:不加密 + */ + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService()); + } + + /** + * 授权规则配置 + */ + @Override + protected void configure(HttpSecurity http) throws Exception { + // 授权配置 + http.authorizeRequests() + .antMatchers("/no-auth/**", "/actuator/**") + .permitAll() + .anyRequest() + .authenticated(); + + // login + http.formLogin() + .loginProcessingUrl("/login") + .successHandler(springSecurityHandler) + .failureHandler(springSecurityHandler) + .permitAll(); + + // no login + http.exceptionHandling() + .authenticationEntryPoint(springSecurityHandler); + + // 本地跨域 + if (projectSetting.getCorsMappings() != null) { + val corsConf = new CorsConfiguration(); + corsConf.setAllowedOrigins(Lists.newArrayList(projectSetting.getCorsMappings())); + corsConf.setAllowedMethods(Lists.newArrayList("*")); + val source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", corsConf); + http.cors().configurationSource(source); + } + + // 时间过滤器 + http.addFilterAfter(bigThreeFilter, SecurityContextPersistenceFilter.class); + + // 不使用session + http.sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); + + http.csrf().disable(); + } } diff --git a/backend/src/main/java/generator/constant/CommonConstant.java b/backend/src/main/java/generator/constant/CommonConstant.java new file mode 100644 index 0000000..cd46b08 --- /dev/null +++ b/backend/src/main/java/generator/constant/CommonConstant.java @@ -0,0 +1,18 @@ +package generator.constant; + +/** + * CommonConstant. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-15 : base version. + */ +public interface CommonConstant { + + + /** + * 日期-时间格式化-字符串 + */ + String DATE_TIME_FORMATTER_STRING = "yyyy-MM-dd HH:mm:ss"; + String RESPONSE_CONTENT_TYPE = "application/json;charset=utf-8"; +} diff --git a/backend/src/main/java/generator/controller/Controller.java b/backend/src/main/java/generator/controller/Controller.java index 3ae517b..dfb3afe 100644 --- a/backend/src/main/java/generator/controller/Controller.java +++ b/backend/src/main/java/generator/controller/Controller.java @@ -1,39 +1,33 @@ package generator.controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.util.List; +import javax.lang.model.type.NullType; -import generator.domain.ArticleType; -import generator.service.ArticleTypeService; +import generator.domain.bo.ArticleInfoBO; +import generator.domain.common.CustomerUser; +import generator.domain.common.ResultData; +import generator.service.ArticleInfoService; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import lombok.val; /** * @author zhaoyiqing */ @RestController @Slf4j +@RequiredArgsConstructor public class Controller { - private final ArticleTypeService articleTypeService; + private final ArticleInfoService articleInfoService; - public Controller(ArticleTypeService articleTypeService) { - this.articleTypeService = articleTypeService; - } - - @GetMapping("/list") - public List list() { - val res = articleTypeService.selectAll(); - log.info("list res [{}]", res); - return res; - } - - /** 登录成功后重定向地址 */ - @RequestMapping("/loginSuccess") - public String loginSuccess() { - return "登录成功"; - } + @PostMapping("/publishArticle") + public ResultData publishArticle(@AuthenticationPrincipal CustomerUser customerUser, + @RequestBody ArticleInfoBO bo) { + articleInfoService.publishArticle(customerUser.getUserInfo().getId(), bo); + return ResultData.success(null); + } } diff --git a/backend/src/main/java/generator/controller/NoAuthController.java b/backend/src/main/java/generator/controller/NoAuthController.java new file mode 100644 index 0000000..ae38a29 --- /dev/null +++ b/backend/src/main/java/generator/controller/NoAuthController.java @@ -0,0 +1,72 @@ +package generator.controller; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +import generator.domain.common.ResultData; +import generator.domain.vo.ArticleInfoVO; +import generator.domain.vo.ArticleTypeVO; +import generator.domain.vo.SearchVO; +import generator.service.ArticleInfoService; +import generator.service.ArticleTypeService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +/** + * NoAuthController. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-15 : base version. + */ +@RestController +@Slf4j +@RequiredArgsConstructor +@RequestMapping("no-auth") +public class NoAuthController { + + private final ArticleTypeService articleTypeService; + + private final ArticleInfoService articleInfoService; + + + @GetMapping("article-type/list") + public ResultData> articleTypeList() { + val res = articleTypeService.selectAll() + .stream() + .map(it -> new ArticleTypeVO().from(it)) + .collect(Collectors.toList()); + return ResultData.success(res); + } + + @GetMapping("article-info/page") + public ResultData> articleInfoPage(Pageable pageable) { + val res = articleInfoService.page(pageable) + .map(it -> new ArticleInfoVO().from(it)); + return ResultData.success(res); + } + + @GetMapping("article-info/search") + public ResultData> articleInfoSearch(String search) { + return ResultData.success(articleInfoService.search(search)); + } + + @GetMapping("article-info/{id}") + public ResultData articleInfoGet(@PathVariable Long id) { + return ResultData.success( + articleInfoService.find(id) + .map(it -> new ArticleInfoVO().from(it)) + .orElseThrow(() -> new RuntimeException("not found" + id)) + + ); + } + +} diff --git a/backend/src/main/java/generator/domain/ArticleInfo.java b/backend/src/main/java/generator/domain/ArticleInfo.java index 8d6a038..241a82e 100644 --- a/backend/src/main/java/generator/domain/ArticleInfo.java +++ b/backend/src/main/java/generator/domain/ArticleInfo.java @@ -1,56 +1,103 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; + import lombok.Data; /** * @author zhaoyiqing @TableName article_info */ -@TableName(value = "article_info") + @Data +@Entity public class ArticleInfo implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** 主键 */ - @TableId private Long id; - /** 文章标题 */ - private String title; - /** 作者id,对应user_info中的id */ - private Long authorId; - /** 发布时间 */ - private Date releaseTime; - /** 文章类型id,对应article_type中的id */ - private Long typeId; - /** 文章浏览量 */ - private Long visitNum; - /** 文章评论量 */ - private Integer commentNum; - /** 悬赏飞吻数 */ - private Integer payKiss; - /** 是否是精华帖,0代表不是,1代表是 */ - private Integer cream; - /** 是否是置顶帖,0代表不是,1代表是 */ - private Integer stick; - /** 是否是否结帖,0代表不是,1代表是 */ - private Integer isDone; - /** 文章内容 */ - private String markdownContent; - /** 文章内容 */ - private String htmlContent; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + @Id + private Long id; + /** + * 文章标题 + */ + private String title; + /** + * 作者id,对应user_info中的id + */ + private Long authorId; + /** + * 发布时间 + */ + private Date releaseTime; + /** + * 文章类型id,对应article_type中的id + */ + private Long typeId; + /** + * 文章浏览量 + */ + private Long visitNum = 0L; + /** + * 文章评论量 + */ + private Integer commentNum = 0; + /** + * 悬赏飞吻数 + */ + private Integer payKiss; + /** + * 是否是精华帖,0代表不是,1代表是 + */ + private Integer cream = 0; + /** + * 是否是置顶帖,0代表不是,1代表是 + */ + private Integer stick = 0; + /** + * 是否是否结帖,0代表不是,1代表是 + */ + private Integer isDone; + /** + * 文章内容 + */ + private String markdownContent; + /** + * 文章内容 + */ + private String htmlContent; + /** + * 0:存在,1:已经被删除 + */ + private Integer state = 0; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; + + @OneToOne + @JoinColumn(name = "authorId", insertable = false, updatable = false) + private UserInfo userInfo; + + @OneToOne + @JoinColumn(name = "typeId", insertable = false, updatable = false) + private ArticleType articleType; } diff --git a/backend/src/main/java/generator/domain/ArticleType.java b/backend/src/main/java/generator/domain/ArticleType.java index ddb6a74..70892a1 100644 --- a/backend/src/main/java/generator/domain/ArticleType.java +++ b/backend/src/main/java/generator/domain/ArticleType.java @@ -1,36 +1,52 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.Id; + import lombok.Data; /** * @author zhaoyiqing @TableName article_type */ -@TableName(value = "article_type") +@Entity @Data public class ArticleType implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** 主键 */ - @TableId private Long id; - /** 类型名 */ - private String typename; - /** 0为普通用户可以获取权限,1为管理员独享权限 */ - private Integer power; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + @Id + private Long id; + /** + * 类型名 + */ + private String typename; + /** + * 0为普通用户可以获取权限,1为管理员独享权限 + */ + private Integer power; + /** + * 0代表存在,1代表已经被删除 + */ + private Integer state; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; } diff --git a/backend/src/main/java/generator/domain/BusinessMsgEnum.java b/backend/src/main/java/generator/domain/BusinessMsgEnum.java index 3b90f29..78a0a07 100644 --- a/backend/src/main/java/generator/domain/BusinessMsgEnum.java +++ b/backend/src/main/java/generator/domain/BusinessMsgEnum.java @@ -2,16 +2,25 @@ /** * 业务异常提示信息枚举类 + * * @author */ public enum BusinessMsgEnum { - /** 参数异常 */ - PARMETER_EXCEPTION ("102", "参数异常!"), - /** 等待超时 */ + /** + * 参数异常 + */ + PARMETER_EXCEPTION("102", "参数异常!"), + /** + * 等待超时 + */ SERVICE_TIME_OUT("103", "服务调用超时!"), - /** 参数过大 */ + /** + * 参数过大 + */ PARMETER_BIG_EXCEPTION("102", "输入的图片数量不能超过50张!"), - /** 500 : 一劳永逸的提示也可以在这定义 */ + /** + * 500 : 一劳永逸的提示也可以在这定义 + */ UNEXPECTED_EXCEPTION("500", "系统发生异常,请联系管理员!"); // 还可以定义更多的业务异常 diff --git a/backend/src/main/java/generator/domain/CollectionInfo.java b/backend/src/main/java/generator/domain/CollectionInfo.java index 039b411..6913251 100644 --- a/backend/src/main/java/generator/domain/CollectionInfo.java +++ b/backend/src/main/java/generator/domain/CollectionInfo.java @@ -1,9 +1,5 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; @@ -12,27 +8,45 @@ /** * @author liubin @TableName collection_info */ -@TableName(value = "collection_info") + @Data public class CollectionInfo implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** 主键 */ - @TableId private Long id; - /** user id */ - private Long collectionId; - /** 收藏文章id */ - private Long articleId; - /** 收藏时间 */ - private Date collectionTime; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + private Long id; + /** + * user id + */ + private Long collectionId; + /** + * 收藏文章id + */ + private Long articleId; + /** + * 收藏时间 + */ + private Date collectionTime; + /** + * 0代表存在,1代表已经被删除 + */ + private Integer state; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; } diff --git a/backend/src/main/java/generator/domain/CommentInfo.java b/backend/src/main/java/generator/domain/CommentInfo.java index e7dc26f..26a2e27 100644 --- a/backend/src/main/java/generator/domain/CommentInfo.java +++ b/backend/src/main/java/generator/domain/CommentInfo.java @@ -1,9 +1,5 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; @@ -14,33 +10,57 @@ * * @author liubin @TableName comment_info */ -@TableName(value = "comment_info") + @Data public class CommentInfo implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** 主键 */ - @TableId private Long id; - /** 评论者id,对应user_info中的id */ - private Long authorId; - /** 发布时间 */ - private Date releaseTime; - /** 文章内容 */ - private String commContent; - /** 评论的文章id */ - private Long articleId; - /** 被点赞的数量 */ - private Integer praisePoints; - /** 是否被采纳,0代表未被采纳,1代表已经被采纳 */ - private Integer isAccept; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + private Long id; + /** + * 评论者id,对应user_info中的id + */ + private Long authorId; + /** + * 发布时间 + */ + private Date releaseTime; + /** + * 文章内容 + */ + private String commContent; + /** + * 评论的文章id + */ + private Long articleId; + /** + * 被点赞的数量 + */ + private Integer praisePoints; + /** + * 是否被采纳,0代表未被采纳,1代表已经被采纳 + */ + private Integer isAccept; + /** + * 0代表存在,1代表已经被删除 + */ + private Integer state; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; } diff --git a/backend/src/main/java/generator/domain/JsonResult.java b/backend/src/main/java/generator/domain/JsonResult.java deleted file mode 100644 index 9103542..0000000 --- a/backend/src/main/java/generator/domain/JsonResult.java +++ /dev/null @@ -1,43 +0,0 @@ -package generator.domain; - -/** - * 异常类 - * @author WangMingXin - * */ -public class JsonResult { - /** - * 异常码 - */ - protected String code; - - /** - * 异常信息 - */ - protected String msg; - - public JsonResult() { - this.code = "200"; - this.msg = "操作成功"; - } - - public JsonResult(String code, String msg) { - this.code = code; - this.msg = msg; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } -} diff --git a/backend/src/main/java/generator/domain/MessageInfo.java b/backend/src/main/java/generator/domain/MessageInfo.java index dba4081..47f6b0c 100644 --- a/backend/src/main/java/generator/domain/MessageInfo.java +++ b/backend/src/main/java/generator/domain/MessageInfo.java @@ -1,9 +1,5 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; @@ -12,33 +8,57 @@ /** * @author liubin @TableName message_info */ -@TableName(value = "message_info") + @Data public class MessageInfo implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** */ - @TableId private Long id; - /** 0代表系统消息;1代表评论消息;2代表点赞消息;3代表采纳评论;4代表管理员公告通知 */ - private Integer messageType; - /** 接受消息的用户id */ - private Long useridTo; - /** 发出消息的用户id */ - private Long useridFrom; - /** 相关文章id */ - private Integer artId; - /** 相关评论id */ - private Integer commentId; - /** 0 未读,1 已读 */ - private Integer read; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * + */ + private Long id; + /** + * 0代表系统消息;1代表评论消息;2代表点赞消息;3代表采纳评论;4代表管理员公告通知 + */ + private Integer messageType; + /** + * 接受消息的用户id + */ + private Long useridTo; + /** + * 发出消息的用户id + */ + private Long useridFrom; + /** + * 相关文章id + */ + private Integer artId; + /** + * 相关评论id + */ + private Integer commentId; + /** + * 0 未读,1 已读 + */ + private Integer read; + /** + * 0代表存在,1代表已经被删除 + */ + private Integer state; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; } diff --git a/backend/src/main/java/generator/domain/PraiseInfo.java b/backend/src/main/java/generator/domain/PraiseInfo.java index 202847b..1375f96 100644 --- a/backend/src/main/java/generator/domain/PraiseInfo.java +++ b/backend/src/main/java/generator/domain/PraiseInfo.java @@ -1,9 +1,5 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; @@ -12,25 +8,41 @@ /** * @author liubin @TableName praise_info */ -@TableName(value = "praise_info") + @Data public class PraiseInfo implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** */ - @TableId private Long id; - /** 点赞者id */ - private Long userid; - /** 评论id */ - private Long commentId; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * + */ + private Long id; + /** + * 点赞者id + */ + private Long userid; + /** + * 评论id + */ + private Long commentId; + /** + * 0代表存在,1代表已经被删除 + */ + private Integer state; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; } diff --git a/backend/src/main/java/generator/domain/UserInfo.java b/backend/src/main/java/generator/domain/UserInfo.java index 0fe75c0..a09fbe2 100644 --- a/backend/src/main/java/generator/domain/UserInfo.java +++ b/backend/src/main/java/generator/domain/UserInfo.java @@ -1,66 +1,105 @@ package generator.domain; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - import java.io.Serializable; import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.Id; + import lombok.Data; /** * @author liubin @TableName user_info */ -@TableName(value = "user_info") + @Data +@Entity public class UserInfo implements Serializable { - @TableField(exist = false) - private static final long serialVersionUID = 1L; - /** 主键 */ - @TableId(type = IdType.AUTO) - private Long id; - /** 邮箱地址 */ - private String email; - /** 用户昵称 */ - private String nickname; - /** 用户名 */ - private String userName; - /** 用户密码 */ - private String password; - /** 头像地址 */ - private String headUrl; - /** 居住城市 */ - private String city; - /** 性别0 男 1 女 */ - private Integer sex; - /** 个人签名 */ - private String sign; - /** 飞吻数 */ - private Integer kissNum; - /** 经验值,发帖回帖涨经验值 */ - private Integer experience; - /** 用户权限 0 代表普通用户,1代表管理员 */ - private Integer authority; - /** 0未激活,1为已经激活 */ - private Boolean active; - /** */ - private String activeCode; - /** 上一次签到天数 */ - private Date lastSign; - /** 连续签到天数 */ - private Integer signDays; - /** 注册时间 */ - private Date regTime; - /** 0代表存在,1代表已经被删除 */ - private Integer state; - /** */ - private Date createTime; - /** */ - private Long createUser; - /** */ - private Date updateTime; - /** */ - private Long updateUser; + + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + @Id + private Long id; + /** + * 邮箱地址 + */ + private String email; + /** + * 用户昵称 + */ + private String nickname; + /** + * 用户密码 + */ + private String password; + /** + * 头像地址 + */ + private String headUrl; + /** + * 居住城市 + */ + private String city; + /** + * 性别0 男 1 女 + */ + private Integer sex; + /** + * 个人签名 + */ + private String sign; + /** + * 飞吻数 + */ + private Integer kissNum; + /** + * 经验值,发帖回帖涨经验值 + */ + private Integer experience; + /** + * 用户权限 0 代表普通用户,1代表管理员 + */ + private Integer authority; + /** + * 0未激活,1为已经激活 + */ + private Boolean active; + /** + * + */ + private String activeCode; + /** + * 上一次签到天数 + */ + private Date lastSign; + /** + * 连续签到天数 + */ + private Integer signDays; + /** + * 注册时间 + */ + private Date regTime; + /** + * 0代表存在,1代表已经被删除 + */ + private Integer state; + /** + * + */ + private Date createTime; + /** + * + */ + private Long createUser; + /** + * + */ + private Date updateTime; + /** + * + */ + private Long updateUser; } diff --git a/backend/src/main/java/generator/domain/bo/ArticleInfoBO.java b/backend/src/main/java/generator/domain/bo/ArticleInfoBO.java new file mode 100644 index 0000000..9444fdd --- /dev/null +++ b/backend/src/main/java/generator/domain/bo/ArticleInfoBO.java @@ -0,0 +1,45 @@ +package generator.domain.bo; + +import generator.domain.ArticleInfo; +import generator.domain.common.Out; +import lombok.Data; + +/** + * ArticleInfoBO. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-17 : base version. + */ +@Data +public class ArticleInfoBO implements Out { + + /** + * 文章标题 + */ + private String title; + + /** + * 文章类型id,对应article_type中的id + */ + private Long typeId; + + + /** + * 悬赏飞吻数 + */ + private Integer payKiss; + + /** + * 是否是否结帖,0代表不是,1代表是 + */ + private Integer isDone; + /** + * 文章内容 + */ + private String markdownContent; + /** + * 文章内容 + */ + private String htmlContent; +} diff --git a/backend/src/main/java/generator/domain/common/CustomerUser.java b/backend/src/main/java/generator/domain/common/CustomerUser.java new file mode 100644 index 0000000..e64d6a5 --- /dev/null +++ b/backend/src/main/java/generator/domain/common/CustomerUser.java @@ -0,0 +1,43 @@ +package generator.domain.common; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; + +import generator.domain.UserInfo; +import lombok.Getter; +import lombok.ToString; + +/** + * CustomerUser. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-16 : base version. + */ +@Getter +@ToString +public class CustomerUser extends User { + + private UserInfo userInfo; + + public CustomerUser(String username, String password, Collection authorities) { + super(username, password, authorities); + } + + public CustomerUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection authorities) { + super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); + } + + public CustomerUser(String username, String password, Collection authorities, UserInfo userInfo) { + super(username, password, authorities); + this.userInfo = userInfo; + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + userInfo.setPassword(null); + } +} diff --git a/backend/src/main/java/generator/domain/common/Out.java b/backend/src/main/java/generator/domain/common/Out.java new file mode 100644 index 0000000..f489776 --- /dev/null +++ b/backend/src/main/java/generator/domain/common/Out.java @@ -0,0 +1,42 @@ +package generator.domain.common; + +import org.springframework.beans.BeanUtils; + +/** + * Out. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-16 : base version. + */ +public interface Out { + /** + * 转换一下 + * + * @param entity 转换实体 + * @return 对象 + */ + + @SuppressWarnings("unchecked") + default V from(E entity) { + BeanUtils.copyProperties(entity, this); + return (V) this; + } + + /** + * zai转换一下 + * + * @param clazz class + * @return obj + */ + default E to(Class clazz) { + E res; + try { + res = clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + BeanUtils.copyProperties(this, res); + return res; + } +} diff --git a/backend/src/main/java/generator/domain/common/ResultCode.java b/backend/src/main/java/generator/domain/common/ResultCode.java index 6d21793..a4fdeee 100644 --- a/backend/src/main/java/generator/domain/common/ResultCode.java +++ b/backend/src/main/java/generator/domain/common/ResultCode.java @@ -3,13 +3,13 @@ /** * @author WangMingXin * @DATE 2022.7.1 七月请对我好一点 - * */ + */ public enum ResultCode { //成功 - SUCCESS(200,"成功"), + SUCCESS(200, "成功"), //参数错误 - PARAM_INVALID(402, "参数输入错误"), + PARAM_INVALID(400, "参数输入错误"), //失败 UNKNOWN_ERROR(500, "未知错误"); diff --git a/backend/src/main/java/generator/domain/common/ResultData.java b/backend/src/main/java/generator/domain/common/ResultData.java index 063350f..e679271 100644 --- a/backend/src/main/java/generator/domain/common/ResultData.java +++ b/backend/src/main/java/generator/domain/common/ResultData.java @@ -1,69 +1,52 @@ package generator.domain.common; +import lombok.Data; + /** * @author WangMingXin - * @DATE 2022.7.1 - * - * */ + */ +@Data public class ResultData { private Integer code; - private String message; + private String msg; private T data; - ResultData() {} - - /** 返回成功 */ + /** + * 返回成功 + */ public static ResultData success() { ResultData resultData = new ResultData<>(); resultData.setCode(ResultCode.SUCCESS.getCode()); - resultData.setMessage(ResultCode.SUCCESS.getMessage()); + resultData.setMsg(ResultCode.SUCCESS.getMessage()); return resultData; } - /** 返回成功 */ + /** + * 返回成功 + */ public static ResultData success(T result) { ResultData resultData = ResultData.success(); resultData.setData(result); return resultData; } - /** 返回失败 */ + /** + * 返回失败 + */ public static ResultData error() { ResultData resultData = new ResultData<>(); resultData.setCode(ResultCode.UNKNOWN_ERROR.getCode()); - resultData.setMessage(ResultCode.UNKNOWN_ERROR.getMessage()); + resultData.setMsg(ResultCode.UNKNOWN_ERROR.getMessage()); return resultData; } - /** 返回失败 */ + /** + * 返回失败 + */ public static ResultData error(T result) { ResultData resultData = ResultData.error(); resultData.setData(result); return resultData; } - - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - } } diff --git a/backend/src/main/java/generator/domain/es/ArticleSearch.java b/backend/src/main/java/generator/domain/es/ArticleSearch.java new file mode 100644 index 0000000..9eef639 --- /dev/null +++ b/backend/src/main/java/generator/domain/es/ArticleSearch.java @@ -0,0 +1,38 @@ +package generator.domain.es; + +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; +import org.springframework.data.elasticsearch.annotations.Mapping; +import org.springframework.data.elasticsearch.annotations.Setting; + +import lombok.Data; + +/** + * @author zhaoyiqing @TableName article_info + */ + +@Data +@Document(indexName = "article-search") +@Setting(settingPath = "/es/index-setting.json") +@Mapping(mappingPath = "/es/article-search.json") +public class ArticleSearch { + + /** + * 主键 + */ + @Id + private Long id; + /** + * 文章标题 + */ + @Field(type = FieldType.Text, analyzer = "ik_max_word,pinyin_word", searchAnalyzer = "ik_max_word,pinyin_word") + private String title; + /** + * 文章内容 + */ + @Field(type = FieldType.Text, analyzer = "ik_max_word,pinyin_word", searchAnalyzer = "ik_max_word,pinyin_word") + private String markdownContent; + +} diff --git a/backend/src/main/java/generator/domain/vo/ArticleInfoVO.java b/backend/src/main/java/generator/domain/vo/ArticleInfoVO.java new file mode 100644 index 0000000..ba100f1 --- /dev/null +++ b/backend/src/main/java/generator/domain/vo/ArticleInfoVO.java @@ -0,0 +1,76 @@ +package generator.domain.vo; + +import java.util.Date; + +import generator.domain.ArticleInfo; +import generator.domain.common.Out; +import lombok.Data; + +/** + * @author zhaoyiqing @TableName article_info + */ + +@Data +public class ArticleInfoVO implements Out { + + /** + * 主键 + */ + private Long id; + /** + * 文章标题 + */ + private String title; + /** + * 作者id,对应user_info中的id + */ + private String authorName; + /** + * 发布时间 + */ + private Date releaseTime; + /** + * 文章类型id,对应article_type中的id + */ + private String typeName; + /** + * 文章浏览量 + */ + private Long visitNum; + /** + * 文章评论量 + */ + private Integer commentNum; + /** + * 悬赏飞吻数 + */ + private Integer payKiss; + /** + * 是否是精华帖,0代表不是,1代表是 + */ + private Integer cream; + /** + * 是否是置顶帖,0代表不是,1代表是 + */ + private Integer stick; + /** + * 是否是否结帖,0代表不是,1代表是 + */ + private Integer isDone; + /** + * 文章内容 + */ + private String markdownContent; + /** + * 文章内容 + */ + private String htmlContent; + + @Override + public ArticleInfoVO from(ArticleInfo entity) { + final ArticleInfoVO res = Out.super.from(entity); + res.setAuthorName(entity.getUserInfo().getNickname()); + res.setTypeName(entity.getArticleType().getTypename()); + return res; + } +} diff --git a/backend/src/main/java/generator/domain/vo/ArticleTypeVO.java b/backend/src/main/java/generator/domain/vo/ArticleTypeVO.java new file mode 100644 index 0000000..9ab82b3 --- /dev/null +++ b/backend/src/main/java/generator/domain/vo/ArticleTypeVO.java @@ -0,0 +1,25 @@ +package generator.domain.vo; + +import generator.domain.ArticleType; +import generator.domain.common.Out; +import lombok.Data; + +/** + * @author zhaoyiqing @TableName article_type + */ +@Data +public class ArticleTypeVO implements Out { + + /** + * 主键 + */ + private Long id; + /** + * 类型名 + */ + private String typename; + /** + * 0为普通用户可以获取权限,1为管理员独享权限 + */ + private Integer power; +} diff --git a/backend/src/main/java/generator/domain/vo/SearchVO.java b/backend/src/main/java/generator/domain/vo/SearchVO.java new file mode 100644 index 0000000..484b8c2 --- /dev/null +++ b/backend/src/main/java/generator/domain/vo/SearchVO.java @@ -0,0 +1,17 @@ +package generator.domain.vo; + +import lombok.Data; + +/** + * SearchVO. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-18 : base version. + */ +@Data +public class SearchVO { + private Long id; + private String title; + private String content; +} diff --git a/backend/src/main/java/generator/domain/vo/UserInVO.java b/backend/src/main/java/generator/domain/vo/UserInVO.java new file mode 100644 index 0000000..bd20964 --- /dev/null +++ b/backend/src/main/java/generator/domain/vo/UserInVO.java @@ -0,0 +1,74 @@ +package generator.domain.vo; + +import java.util.Date; + +import generator.domain.UserInfo; +import generator.domain.common.Out; +import lombok.Data; + +/** + * @author liubin @TableName user_info + */ + +@Data +public class UserInVO implements Out { + + /** + * 主键 + */ + private Long id; + /** + * 邮箱地址 + */ + private String email; + /** + * 用户昵称 + */ + private String nickname; + + /** + * 头像地址 + */ + private String headUrl; + /** + * 居住城市 + */ + private String city; + /** + * 性别0 男 1 女 + */ + private Integer sex; + /** + * 个人签名 + */ + private String sign; + /** + * 飞吻数 + */ + private Integer kissNum; + /** + * 经验值,发帖回帖涨经验值 + */ + private Integer experience; + /** + * 用户权限 0 代表普通用户,1代表管理员 + */ + private Integer authority; + + /** + * 0未激活,1为已经激活 + */ + private Boolean active; + /** + * + */ + private String activeCode; + /** + * 上一次签到天数 + */ + private Date lastSign; + /** + * 连续签到天数 + */ + private Integer signDays; +} diff --git a/backend/src/main/java/generator/filter/BigThreeFilter.java b/backend/src/main/java/generator/filter/BigThreeFilter.java index a8a45b2..de9ad8a 100644 --- a/backend/src/main/java/generator/filter/BigThreeFilter.java +++ b/backend/src/main/java/generator/filter/BigThreeFilter.java @@ -20,13 +20,13 @@ @Slf4j public class BigThreeFilter extends OncePerRequestFilter { - @Override - protected void doFilterInternal( - HttpServletRequest request, @NonNull HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - String requestUri = request.getRequestURI(); - long start = System.currentTimeMillis(); - filterChain.doFilter(request, response); - log.info("uri [{}],use [{}]ms", requestUri, (System.currentTimeMillis() - start)); - } + @Override + protected void doFilterInternal( + HttpServletRequest request, @NonNull HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + String requestUri = request.getRequestURI(); + long start = System.currentTimeMillis(); + filterChain.doFilter(request, response); + log.info("uri [{}],use [{}]ms", requestUri, (System.currentTimeMillis() - start)); + } } diff --git a/backend/src/main/java/generator/filter/WebLogAspect.java b/backend/src/main/java/generator/filter/WebLogAspect.java new file mode 100644 index 0000000..b1bee1d --- /dev/null +++ b/backend/src/main/java/generator/filter/WebLogAspect.java @@ -0,0 +1,54 @@ +package generator.filter; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; +import lombok.val; + +/** + * WebLogAspect. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-15 : base version. + */ +@Aspect +@Component +@Slf4j +public class WebLogAspect { + + private final ObjectMapper objectMapper; + + public WebLogAspect(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * 以 controller 包下定义的所有请求为切入点. + */ + @Pointcut("execution(* generator.controller..*.*(..))") + public void webLog() { + + } + + /** + * 在切点之前织入 + * + * @param joinPoint joinPoint对象 + */ + @Before("webLog()") + public void doBefore(JoinPoint joinPoint) throws JsonProcessingException { + log.info("execution : [{}]", joinPoint.toLongString()); + val args = joinPoint.getArgs(); + val argsStr = objectMapper.writer().writeValueAsString(args); + log.info("args : [{}]", argsStr); + } + +} diff --git a/backend/src/main/java/generator/globalexception/BusinessErrorException.java b/backend/src/main/java/generator/globalexception/BusinessErrorException.java index 37ed7b4..ece09dc 100644 --- a/backend/src/main/java/generator/globalexception/BusinessErrorException.java +++ b/backend/src/main/java/generator/globalexception/BusinessErrorException.java @@ -2,11 +2,16 @@ import generator.domain.BusinessMsgEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; /** * 自定义业务异常 - * @author + * + * @author wmx */ +@Data +@EqualsAndHashCode(callSuper = false) public class BusinessErrorException extends RuntimeException { private static final long serialVersionUID = -7480022450501760611L; @@ -24,22 +29,4 @@ public BusinessErrorException(BusinessMsgEnum businessMsgEnum) { this.code = businessMsgEnum.getCode(); this.message = businessMsgEnum.getMsg(); } - // get set方法 - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - @Override - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } } diff --git a/backend/src/main/java/generator/globalexception/GlobalExceptionHandler.java b/backend/src/main/java/generator/globalexception/GlobalExceptionHandler.java index 9bbddea..264dbe2 100644 --- a/backend/src/main/java/generator/globalexception/GlobalExceptionHandler.java +++ b/backend/src/main/java/generator/globalexception/GlobalExceptionHandler.java @@ -7,7 +7,9 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; -import generator.domain.JsonResult; +import javax.lang.model.type.NullType; + +import generator.domain.common.ResultData; import lombok.extern.slf4j.Slf4j; /** @@ -20,58 +22,57 @@ @Slf4j public class GlobalExceptionHandler { - /** - * 系统异常 预期以外异常 - * - * @param ex Exception - * @return JsonResult - */ - @ExceptionHandler(Exception.class) - @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) - public JsonResult handleUnexpectedServer(Exception ex) { - log.error("系统异常:", ex); - ex.printStackTrace(); - return new JsonResult("500", "系统发生异常,请联系管理员"); - } + /** + * 系统异常 预期以外异常 + * + * @param ex Exception + * @return generator.domain.common.ResultData + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) + public ResultData handleUnexpectedServer(Exception ex) { + log.error("系统异常:", ex); + return ResultData.error(); + } - /** - * 缺少请求参数异常 - * - * @param ex HttpMessageNotReadableException - * @return JsonResult - */ - @ExceptionHandler(MissingServletRequestParameterException.class) - @ResponseStatus(value = HttpStatus.BAD_REQUEST) - public JsonResult handleHttpMessageNotReadableException( - MissingServletRequestParameterException ex) { - log.error("缺少请求参数,{}", ex.getMessage()); - return new JsonResult("400", "缺少请求参数"); - } + /** + * 缺少请求参数异常 + * + * @param ex HttpMessageNotReadableException + * @return ResultData + */ + @ExceptionHandler(MissingServletRequestParameterException.class) + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public ResultData handleHttpMessageNotReadableException( + MissingServletRequestParameterException ex) { + log.error("缺少请求参数,{}", ex.getMessage()); + return ResultData.error(); + } - /** - * 空指针异常 - * - * @param ex NullPointerException - * @return JsonResult - */ - @ExceptionHandler(NullPointerException.class) - @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) - public JsonResult handleTypeMismatchException(NullPointerException ex) { - log.error("空指针异常,{}", ex.getMessage()); - return new JsonResult("500", "空指针异常"); - } + /** + * 空指针异常 + * + * @param ex NullPointerException + * @return ResultData + */ + @ExceptionHandler(NullPointerException.class) + @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) + public ResultData handleTypeMismatchException(NullPointerException ex) { + log.error("空指针异常,{}", ex.getMessage()); + return ResultData.error(); + } - /** - * 拦截业务异常,返回业务异常信息 - * - * @param ex BusinessErrorException - * @return JsonResult - */ - @ExceptionHandler(BusinessErrorException.class) - @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) - public JsonResult handleBusinessError(BusinessErrorException ex) { - String code = ex.getCode(); - String message = ex.getMessage(); - return new JsonResult(code, message); - } + /** + * 拦截业务异常,返回业务异常信息 + * + * @param ex BusinessErrorException + * @return ResultData<> + */ + @ExceptionHandler(BusinessErrorException.class) + @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) + public ResultData handleBusinessError(BusinessErrorException ex) { + final ResultData res = ResultData.error(); + res.setMsg(ex.getMessage()); + return res; + } } diff --git a/backend/src/main/java/generator/mapper/ArticleInfoMapper.java b/backend/src/main/java/generator/mapper/ArticleInfoMapper.java index d441b2e..861ebe4 100644 --- a/backend/src/main/java/generator/mapper/ArticleInfoMapper.java +++ b/backend/src/main/java/generator/mapper/ArticleInfoMapper.java @@ -1,9 +1,9 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - import org.apache.ibatis.annotations.Mapper; +import java.util.List; + import generator.domain.ArticleInfo; /** @@ -12,4 +12,12 @@ * @createDate 2022-06-08 09:53:40 @Entity generator.domain.ArticleInfo */ @Mapper -public interface ArticleInfoMapper extends BaseMapper {} +public interface ArticleInfoMapper { + + /** + * 获取分类的top5 访问量排序 + * + * @return 集合 + */ + List groupByTypeTop5(); +} diff --git a/backend/src/main/java/generator/mapper/ArticleTypeMapper.java b/backend/src/main/java/generator/mapper/ArticleTypeMapper.java index 5544623..aff4490 100644 --- a/backend/src/main/java/generator/mapper/ArticleTypeMapper.java +++ b/backend/src/main/java/generator/mapper/ArticleTypeMapper.java @@ -1,8 +1,9 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; import generator.domain.ArticleType; @@ -12,4 +13,24 @@ * @createDate 2022-06-08 09:28:25 @Entity generator.domain.ArticleType */ @Mapper -public interface ArticleTypeMapper extends BaseMapper {} +public interface ArticleTypeMapper { + + + /** + * sql 注入 + * + * @param column 列明 + * @param order desc + * @return 集合 + */ + List findAllOrder(@Param("column") String column, @Param("order") String order); + + /** + * sql 注入 + * + * @param table 表 + * @return 集合 + */ + List findAllByTable(String table); + +} diff --git a/backend/src/main/java/generator/mapper/CollectionInfoMapper.java b/backend/src/main/java/generator/mapper/CollectionInfoMapper.java index df29b09..e5f161f 100644 --- a/backend/src/main/java/generator/mapper/CollectionInfoMapper.java +++ b/backend/src/main/java/generator/mapper/CollectionInfoMapper.java @@ -1,12 +1,9 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -import generator.domain.CollectionInfo; - /** * @author HangZ * @description 针对表【collection_info】的数据库操作Mapper * @createDate 2022-06-08 16:26:12 @Entity generator.domain.CollectionInfo */ -public interface CollectionInfoMapper extends BaseMapper {} +public interface CollectionInfoMapper { +} diff --git a/backend/src/main/java/generator/mapper/CommentInfoMapper.java b/backend/src/main/java/generator/mapper/CommentInfoMapper.java index eb65d6b..23c3455 100644 --- a/backend/src/main/java/generator/mapper/CommentInfoMapper.java +++ b/backend/src/main/java/generator/mapper/CommentInfoMapper.java @@ -1,12 +1,9 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -import generator.domain.CommentInfo; - /** * @author HangZ * @description 针对表【comment_info】的数据库操作Mapper * @createDate 2022-06-08 16:26:18 @Entity generator.domain.CommentInfo */ -public interface CommentInfoMapper extends BaseMapper {} +public interface CommentInfoMapper { +} diff --git a/backend/src/main/java/generator/mapper/MessageInfoMapper.java b/backend/src/main/java/generator/mapper/MessageInfoMapper.java index f14cece..59ac718 100644 --- a/backend/src/main/java/generator/mapper/MessageInfoMapper.java +++ b/backend/src/main/java/generator/mapper/MessageInfoMapper.java @@ -1,12 +1,9 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -import generator.domain.MessageInfo; - /** * @author HangZ * @description 针对表【message_info】的数据库操作Mapper * @createDate 2022-06-08 16:26:20 @Entity generator.domain.MessageInfo */ -public interface MessageInfoMapper extends BaseMapper {} +public interface MessageInfoMapper { +} diff --git a/backend/src/main/java/generator/mapper/PraiseInfoMapper.java b/backend/src/main/java/generator/mapper/PraiseInfoMapper.java index e1f1a32..b2cfa8d 100644 --- a/backend/src/main/java/generator/mapper/PraiseInfoMapper.java +++ b/backend/src/main/java/generator/mapper/PraiseInfoMapper.java @@ -1,12 +1,9 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -import generator.domain.PraiseInfo; - /** * @author HangZ * @description 针对表【praise_info】的数据库操作Mapper * @createDate 2022-06-08 16:26:24 @Entity generator.domain.PraiseInfo */ -public interface PraiseInfoMapper extends BaseMapper {} +public interface PraiseInfoMapper { +} diff --git a/backend/src/main/java/generator/mapper/UserInfoMapper.java b/backend/src/main/java/generator/mapper/UserInfoMapper.java index 62d3ee2..bacb92e 100644 --- a/backend/src/main/java/generator/mapper/UserInfoMapper.java +++ b/backend/src/main/java/generator/mapper/UserInfoMapper.java @@ -1,16 +1,15 @@ package generator.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; import generator.domain.UserInfo; -import org.apache.ibatis.annotations.Param; /** * @author HangZ * @description 针对表【user_info】的数据库操作Mapper * @createDate 2022-06-08 16:26:27 @Entity generator.domain.UserInfo */ -public interface UserInfoMapper extends BaseMapper { +public interface UserInfoMapper { /** * 根据用户名查询用户 diff --git a/backend/src/main/java/generator/repository/ArticleInfoRepository.java b/backend/src/main/java/generator/repository/ArticleInfoRepository.java new file mode 100644 index 0000000..51e90e4 --- /dev/null +++ b/backend/src/main/java/generator/repository/ArticleInfoRepository.java @@ -0,0 +1,18 @@ +package generator.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import generator.domain.ArticleInfo; + +/** + * ArticleInfoRepository. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-11 : base version. + */ +@Repository +public interface ArticleInfoRepository extends JpaRepository { + +} diff --git a/backend/src/main/java/generator/repository/ArticleSearchRepository.java b/backend/src/main/java/generator/repository/ArticleSearchRepository.java new file mode 100644 index 0000000..239355c --- /dev/null +++ b/backend/src/main/java/generator/repository/ArticleSearchRepository.java @@ -0,0 +1,36 @@ +package generator.repository; + +import org.springframework.data.elasticsearch.annotations.Highlight; +import org.springframework.data.elasticsearch.annotations.HighlightField; +import org.springframework.data.elasticsearch.annotations.HighlightParameters; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +import generator.domain.es.ArticleSearch; + +/** + * ArticleSearchRepository. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-18 : base version. + */ +@Repository +public interface ArticleSearchRepository extends ElasticsearchRepository { + + /** + * 搜索文章 + * + * @param title 标题 + * @param content 内容 + * @return list + */ + @Highlight(fields = { + @HighlightField(name = "title", parameters = @HighlightParameters(preTags = "", postTags = "")), + @HighlightField(name = "markdownContent", parameters = @HighlightParameters(preTags = "", postTags = "")) + }) + List> findByTitleOrMarkdownContent(String title, String content); +} diff --git a/backend/src/main/java/generator/service/ArticleInfoService.java b/backend/src/main/java/generator/service/ArticleInfoService.java index 6d34be0..4610af2 100644 --- a/backend/src/main/java/generator/service/ArticleInfoService.java +++ b/backend/src/main/java/generator/service/ArticleInfoService.java @@ -1,10 +1,15 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.Optional; + import generator.domain.ArticleInfo; +import generator.domain.bo.ArticleInfoBO; +import generator.domain.vo.SearchVO; /** * @author HangZ @@ -12,4 +17,36 @@ * @createDate 2022-06-08 09:53:40 */ @Service -public interface ArticleInfoService extends IService {} +public interface ArticleInfoService { + + /** + * page article info page + * + * @param pageable pageable + * @return page obj + */ + Page page(Pageable pageable); + + /** + * 发布文章 + * + * @param userId user + * @param bo article + */ + void publishArticle(Long userId, ArticleInfoBO bo); + + /** + * 搜索文章 + * + * @param search 字符 + * @return page obj + */ + List search(String search); + + /** + * 文章信息 + * @param id id + * @return obj + */ + Optional find(Long id); +} diff --git a/backend/src/main/java/generator/service/ArticleTypeService.java b/backend/src/main/java/generator/service/ArticleTypeService.java index afe7b00..d726454 100644 --- a/backend/src/main/java/generator/service/ArticleTypeService.java +++ b/backend/src/main/java/generator/service/ArticleTypeService.java @@ -1,7 +1,5 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - import org.springframework.stereotype.Service; import java.util.List; @@ -14,11 +12,11 @@ * @createDate 2022-06-08 09:28:25 */ @Service -public interface ArticleTypeService extends IService { - /** - * selectAll - * - * @return list - */ - List selectAll(); +public interface ArticleTypeService { + /** + * selectAll + * + * @return list + */ + List selectAll(); } diff --git a/backend/src/main/java/generator/service/CollectionInfoService.java b/backend/src/main/java/generator/service/CollectionInfoService.java index 48cb5f1..1df691b 100644 --- a/backend/src/main/java/generator/service/CollectionInfoService.java +++ b/backend/src/main/java/generator/service/CollectionInfoService.java @@ -1,12 +1,9 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - -import generator.domain.CollectionInfo; - /** * @author HangZ * @description 针对表【collection_info】的数据库操作Service * @createDate 2022-06-08 16:26:12 */ -public interface CollectionInfoService extends IService {} +public interface CollectionInfoService { +} diff --git a/backend/src/main/java/generator/service/CommentInfoService.java b/backend/src/main/java/generator/service/CommentInfoService.java index 3b5adba..f8412f6 100644 --- a/backend/src/main/java/generator/service/CommentInfoService.java +++ b/backend/src/main/java/generator/service/CommentInfoService.java @@ -1,12 +1,9 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - -import generator.domain.CommentInfo; - /** * @author HangZ * @description 针对表【comment_info】的数据库操作Service * @createDate 2022-06-08 16:26:18 */ -public interface CommentInfoService extends IService {} +public interface CommentInfoService { +} diff --git a/backend/src/main/java/generator/service/MessageInfoService.java b/backend/src/main/java/generator/service/MessageInfoService.java index 7402abc..d1b2d8e 100644 --- a/backend/src/main/java/generator/service/MessageInfoService.java +++ b/backend/src/main/java/generator/service/MessageInfoService.java @@ -1,12 +1,9 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - -import generator.domain.MessageInfo; - /** * @author HangZ * @description 针对表【message_info】的数据库操作Service * @createDate 2022-06-08 16:26:20 */ -public interface MessageInfoService extends IService {} +public interface MessageInfoService { +} diff --git a/backend/src/main/java/generator/service/PraiseInfoService.java b/backend/src/main/java/generator/service/PraiseInfoService.java index ccfe809..bad40eb 100644 --- a/backend/src/main/java/generator/service/PraiseInfoService.java +++ b/backend/src/main/java/generator/service/PraiseInfoService.java @@ -1,12 +1,9 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - -import generator.domain.PraiseInfo; - /** * @author HangZ * @description 针对表【praise_info】的数据库操作Service * @createDate 2022-06-08 16:26:24 */ -public interface PraiseInfoService extends IService {} +public interface PraiseInfoService { +} diff --git a/backend/src/main/java/generator/service/SysUserService.java b/backend/src/main/java/generator/service/SysUserService.java deleted file mode 100644 index 12a9a47..0000000 --- a/backend/src/main/java/generator/service/SysUserService.java +++ /dev/null @@ -1,18 +0,0 @@ -package generator.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import generator.domain.UserInfo; - -/** - * 用户service - * @author WangMingXin - * */ -public interface SysUserService extends IService { - /** - * 根据用户名查询用户 - * - * @param userName - * @return - */ - UserInfo selectByUserName(String userName); -} diff --git a/backend/src/main/java/generator/service/UserInfoService.java b/backend/src/main/java/generator/service/UserInfoService.java index 6fcbe7c..6fbbc2f 100644 --- a/backend/src/main/java/generator/service/UserInfoService.java +++ b/backend/src/main/java/generator/service/UserInfoService.java @@ -1,12 +1,9 @@ package generator.service; -import com.baomidou.mybatisplus.extension.service.IService; - -import generator.domain.UserInfo; - /** * @author HangZ * @description 针对表【user_info】的数据库操作Service * @createDate 2022-06-08 16:26:27 */ -public interface UserInfoService extends IService {} +public interface UserInfoService { +} diff --git a/backend/src/main/java/generator/service/impl/ArticleInfoServiceImpl.java b/backend/src/main/java/generator/service/impl/ArticleInfoServiceImpl.java index 96a36b7..d4533dd 100644 --- a/backend/src/main/java/generator/service/impl/ArticleInfoServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/ArticleInfoServiceImpl.java @@ -1,12 +1,27 @@ package generator.service.impl; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import generator.domain.ArticleInfo; -import generator.mapper.ArticleInfoMapper; +import generator.domain.bo.ArticleInfoBO; +import generator.domain.es.ArticleSearch; +import generator.domain.vo.SearchVO; +import generator.repository.ArticleInfoRepository; +import generator.repository.ArticleSearchRepository; import generator.service.ArticleInfoService; +import lombok.val; /** * @author HangZ @@ -14,5 +29,58 @@ * @createDate 2022-06-08 09:53:40 */ @Service -public class ArticleInfoServiceImpl extends ServiceImpl - implements ArticleInfoService {} +public class ArticleInfoServiceImpl + implements ArticleInfoService { + + private final ArticleInfoRepository articleInfoRepository; + private final ArticleSearchRepository articleSearchRepository; + + public ArticleInfoServiceImpl(ArticleInfoRepository articleInfoRepository, ArticleSearchRepository articleSearchRepository) { + this.articleInfoRepository = articleInfoRepository; + this.articleSearchRepository = articleSearchRepository; + } + + @Override + public Page page(Pageable pageable) { + return articleInfoRepository.findAll(pageable); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void publishArticle(Long userId, ArticleInfoBO bo) { + val articleInfo = bo.to(ArticleInfo.class); + articleInfo.setAuthorId(userId); + articleInfo.setCreateUser(userId); + articleInfo.setReleaseTime(new Date()); + articleInfo.setCreateTime(new Date()); + articleInfo.setId(System.currentTimeMillis()); + articleInfoRepository.saveAndFlush(articleInfo); + + val search = new ArticleSearch(); + search.setId(articleInfo.getId()); + search.setTitle(bo.getTitle()); + search.setMarkdownContent(bo.getMarkdownContent()); + articleSearchRepository.save(search); + } + + @Override + public List search(String search) { + return articleSearchRepository.findByTitleOrMarkdownContent(search, search) + .stream() + .map(it -> { + final SearchVO res = new SearchVO(); + final ArticleSearch content = it.getContent(); + res.setId(content.getId()); + final Map> highlightFields = it.getHighlightFields(); + res.setTitle(highlightFields.getOrDefault("title", Lists.newArrayList(content.getTitle())).get(0)); + res.setContent(highlightFields.getOrDefault("markdownContent", Collections.singletonList("")).get(0)); + return res; + }) + .collect(Collectors.toList()); + } + + @Override + public Optional find(Long id) { + return articleInfoRepository.findById(id); + } +} diff --git a/backend/src/main/java/generator/service/impl/ArticleTypeServiceImpl.java b/backend/src/main/java/generator/service/impl/ArticleTypeServiceImpl.java index d216224..7f81d11 100644 --- a/backend/src/main/java/generator/service/impl/ArticleTypeServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/ArticleTypeServiceImpl.java @@ -1,7 +1,5 @@ package generator.service.impl; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - import org.springframework.stereotype.Service; import java.util.List; @@ -16,17 +14,17 @@ * @createDate 2022-06-08 09:28:25 */ @Service -public class ArticleTypeServiceImpl extends ServiceImpl - implements ArticleTypeService { +public class ArticleTypeServiceImpl + implements ArticleTypeService { - private final ArticleTypeMapper articleTypeMapper; + private final ArticleTypeMapper articleTypeMapper; - public ArticleTypeServiceImpl(ArticleTypeMapper articleTypeMapper) { - this.articleTypeMapper = articleTypeMapper; - } + public ArticleTypeServiceImpl(ArticleTypeMapper articleTypeMapper) { + this.articleTypeMapper = articleTypeMapper; + } - @Override - public List selectAll() { - return articleTypeMapper.selectList(null); - } + @Override + public List selectAll() { + return articleTypeMapper.findAllOrder("id", "desc"); + } } diff --git a/backend/src/main/java/generator/service/impl/CollectionInfoServiceImpl.java b/backend/src/main/java/generator/service/impl/CollectionInfoServiceImpl.java index 5274175..c0e8f6f 100644 --- a/backend/src/main/java/generator/service/impl/CollectionInfoServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/CollectionInfoServiceImpl.java @@ -1,11 +1,7 @@ package generator.service.impl; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - import org.springframework.stereotype.Service; -import generator.domain.CollectionInfo; -import generator.mapper.CollectionInfoMapper; import generator.service.CollectionInfoService; /** @@ -14,5 +10,6 @@ * @createDate 2022-06-08 16:26:12 */ @Service -public class CollectionInfoServiceImpl extends ServiceImpl - implements CollectionInfoService {} +public class CollectionInfoServiceImpl + implements CollectionInfoService { +} diff --git a/backend/src/main/java/generator/service/impl/CommentInfoServiceImpl.java b/backend/src/main/java/generator/service/impl/CommentInfoServiceImpl.java index 44047b3..9d90d7e 100644 --- a/backend/src/main/java/generator/service/impl/CommentInfoServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/CommentInfoServiceImpl.java @@ -1,11 +1,7 @@ package generator.service.impl; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - import org.springframework.stereotype.Service; -import generator.domain.CommentInfo; -import generator.mapper.CommentInfoMapper; import generator.service.CommentInfoService; /** @@ -14,5 +10,6 @@ * @createDate 2022-06-08 16:26:18 */ @Service -public class CommentInfoServiceImpl extends ServiceImpl - implements CommentInfoService {} +public class CommentInfoServiceImpl + implements CommentInfoService { +} diff --git a/backend/src/main/java/generator/service/impl/MessageInfoServiceImpl.java b/backend/src/main/java/generator/service/impl/MessageInfoServiceImpl.java index f797412..cfe848d 100644 --- a/backend/src/main/java/generator/service/impl/MessageInfoServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/MessageInfoServiceImpl.java @@ -1,11 +1,7 @@ package generator.service.impl; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - import org.springframework.stereotype.Service; -import generator.domain.MessageInfo; -import generator.mapper.MessageInfoMapper; import generator.service.MessageInfoService; /** @@ -14,5 +10,6 @@ * @createDate 2022-06-08 16:26:20 */ @Service -public class MessageInfoServiceImpl extends ServiceImpl - implements MessageInfoService {} +public class MessageInfoServiceImpl + implements MessageInfoService { +} diff --git a/backend/src/main/java/generator/service/impl/PraiseInfoServiceImpl.java b/backend/src/main/java/generator/service/impl/PraiseInfoServiceImpl.java index 4ea919f..c48848f 100644 --- a/backend/src/main/java/generator/service/impl/PraiseInfoServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/PraiseInfoServiceImpl.java @@ -1,11 +1,7 @@ package generator.service.impl; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - import org.springframework.stereotype.Service; -import generator.domain.PraiseInfo; -import generator.mapper.PraiseInfoMapper; import generator.service.PraiseInfoService; /** @@ -14,5 +10,6 @@ * @createDate 2022-06-08 16:26:24 */ @Service -public class PraiseInfoServiceImpl extends ServiceImpl - implements PraiseInfoService {} +public class PraiseInfoServiceImpl + implements PraiseInfoService { +} diff --git a/backend/src/main/java/generator/service/impl/SysUserServiceImpl.java b/backend/src/main/java/generator/service/impl/SysUserServiceImpl.java deleted file mode 100644 index 2fc2e9e..0000000 --- a/backend/src/main/java/generator/service/impl/SysUserServiceImpl.java +++ /dev/null @@ -1,29 +0,0 @@ -package generator.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import generator.domain.UserInfo; -import generator.mapper.UserInfoMapper; -import generator.service.SysUserService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * - * @author WangMingXin - * */ -@Service -public class SysUserServiceImpl extends ServiceImpl implements SysUserService { - @Autowired - private UserInfoMapper userInfoMapper; - - /** - * 根据用户名查询用户 - * - * @param userName - * @return - */ - @Override - public UserInfo selectByUserName(String userName) { - return userInfoMapper.selectByUserName(userName); - } -} diff --git a/backend/src/main/java/generator/service/impl/UserDetailsServiceImpl.java b/backend/src/main/java/generator/service/impl/UserDetailsServiceImpl.java index d10811c..ee5a5b5 100644 --- a/backend/src/main/java/generator/service/impl/UserDetailsServiceImpl.java +++ b/backend/src/main/java/generator/service/impl/UserDetailsServiceImpl.java @@ -1,39 +1,42 @@ package generator.service.impl; -import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import generator.domain.UserInfo; -import generator.service.SysUserService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.userdetails.User; +import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import javax.annotation.Resource; import java.util.ArrayList; +import java.util.Optional; + +import generator.domain.common.CustomerUser; +import generator.mapper.UserInfoMapper; +import generator.service.UserInfoService; +import lombok.RequiredArgsConstructor; /** - *刘b 我真求求了 把阿里规范去了吧 + * 刘b 我真求求了 把阿里规范去了吧 + * * @author WangMingXin - * */ -@Service -public class UserDetailsServiceImpl implements UserDetailsService { - @Resource - private SysUserService sysUserService; + */ +@Service("UserDetailsServiceImpl") +@RequiredArgsConstructor +public class UserDetailsServiceImpl implements UserDetailsService, UserInfoService { + + private final UserInfoMapper userInfoMapper; - /** 根据userName 查询用户信息 */ + /** + * 根据userName 查询用户信息 + */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //需要构造出 org.springframework.security.core.userdetails.User 对象并返回 - if(StringUtils.isBlank(username)){ + if (StringUtils.isBlank(username)) { throw new RuntimeException("用户不能为空"); } - UserInfo userInfo = sysUserService.selectByUserName(username); - if (userInfo == null) { - throw new RuntimeException("用户不存在"); - } - return new User(userInfo.getNickname(), userInfo.getPassword(), true, true, true, true,new ArrayList<>()); + return Optional.ofNullable(userInfoMapper.selectByUserName(username)) + .map(it -> new CustomerUser(it.getEmail(), it.getPassword(), new ArrayList<>(), it)) + .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); } } diff --git a/backend/src/main/java/generator/service/impl/UserInfoServiceImpl.java b/backend/src/main/java/generator/service/impl/UserInfoServiceImpl.java deleted file mode 100644 index 105ad7a..0000000 --- a/backend/src/main/java/generator/service/impl/UserInfoServiceImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package generator.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - -import org.springframework.stereotype.Service; - -import generator.domain.UserInfo; -import generator.mapper.UserInfoMapper; -import generator.service.UserInfoService; - -/** - * @author HangZ - * @description 针对表【user_info】的数据库操作Service实现 - * @createDate 2022-06-08 16:26:27 - */ -@Service -public class UserInfoServiceImpl extends ServiceImpl - implements UserInfoService {} diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml index 6aa332d..167c780 100644 --- a/backend/src/main/resources/application-dev.yml +++ b/backend/src/main/resources/application-dev.yml @@ -4,6 +4,10 @@ spring: password: big_three url: jdbc:mysql://127.0.0.1:3306/big_three?characterEncoding=UTF-8&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver + + elasticsearch: + uris: http://localhost:9200 + big-three: cors-mappings: - http://127.0.0.1:7001 diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index 04d4753..695778d 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -3,4 +3,7 @@ spring: username: big_three password: big_three url: jdbc:mysql://mysql:3306/big_three?characterEncoding=UTF-8&serverTimezone=UTC - driver-class-name: com.mysql.cj.jdbc.Driver \ No newline at end of file + driver-class-name: com.mysql.cj.jdbc.Driver + + elasticsearch: + uris: http://elasticsearch:9200 \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index df9e03f..e1fb6a3 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -3,6 +3,13 @@ spring: name: big-three profiles: active: dev + data: + web: + pageable: + one-indexed-parameters: true + jpa: + hibernate: + ddl-auto: none server: port: 8080 servlet: @@ -14,4 +21,12 @@ management: include: health endpoint: health: - show-details: always \ No newline at end of file + show-details: always +mybatis: + mapper-locations: classpath:mapper/**/*.xml +logging: + level: + org.hibernate.SQL: DEBUG + org.hibernate.type.descriptor.sql.BasicBinder: TRACE + org.springframework.data.elasticsearch.client.WIRE: TRACE + root: INFO \ No newline at end of file diff --git a/backend/src/main/resources/es/article-search.json b/backend/src/main/resources/es/article-search.json new file mode 100644 index 0000000..c08d21d --- /dev/null +++ b/backend/src/main/resources/es/article-search.json @@ -0,0 +1,28 @@ +{ + "properties": { + "title": { + "type": "text", + "analyzer": "ikSearchAnalyzer", + "search_analyzer": "ikSearchAnalyzer", + "fields": { + "pinyin": { + "type": "text", + "analyzer": "pinyinSimpleIndexAnalyzer", + "search_analyzer": "pinyinSimpleIndexAnalyzer" + } + } + }, + "markdownContent": { + "type": "text", + "analyzer": "ikSearchAnalyzer", + "search_analyzer": "ikSearchAnalyzer", + "fields": { + "pinyin": { + "type": "text", + "analyzer": "pinyinSimpleIndexAnalyzer", + "search_analyzer": "pinyinSimpleIndexAnalyzer" + } + } + } + } +} diff --git a/backend/src/main/resources/es/index-setting.json b/backend/src/main/resources/es/index-setting.json new file mode 100644 index 0000000..67e6fcf --- /dev/null +++ b/backend/src/main/resources/es/index-setting.json @@ -0,0 +1,28 @@ +{ + "analysis": { + "number_of_shards": "1", + "number_of_replicas": "0", + "analyzer": { + "ikSearchAnalyzer": { + "type": "custom", + "tokenizer": "ik_max_word" + }, + "pinyinSimpleIndexAnalyzer": { + "tokenizer": "pinyin_word" + } + }, + "tokenizer": { + "pinyin_word": { + "type": "pinyin", + "first_letter": "prefix", + "padding_char": " ", + "keep_first_letter": true, + "keep_separate_first_letter": true, + "keep_full_pinyin": true, + "keep_original": false, + "limit_first_letter_length": 16, + "lowercase": true + } + } + } +} \ No newline at end of file diff --git a/backend/src/main/resources/mapper/ArticleInfoMapper.xml b/backend/src/main/resources/mapper/ArticleInfoMapper.xml index 4315df9..37235de 100644 --- a/backend/src/main/resources/mapper/ArticleInfoMapper.xml +++ b/backend/src/main/resources/mapper/ArticleInfoMapper.xml @@ -33,4 +33,27 @@ html_content,state,create_time, create_user,update_time,update_user + diff --git a/backend/src/main/resources/mapper/ArticleTypeMapper.xml b/backend/src/main/resources/mapper/ArticleTypeMapper.xml index 9a53cb6..8253022 100644 --- a/backend/src/main/resources/mapper/ArticleTypeMapper.xml +++ b/backend/src/main/resources/mapper/ArticleTypeMapper.xml @@ -20,4 +20,22 @@ state,create_time,create_user, update_time,update_user + + diff --git a/backend/src/main/resources/mapper/UserInfoMapper.xml b/backend/src/main/resources/mapper/UserInfoMapper.xml index d3efd08..54bb164 100644 --- a/backend/src/main/resources/mapper/UserInfoMapper.xml +++ b/backend/src/main/resources/mapper/UserInfoMapper.xml @@ -28,18 +28,30 @@ - - id,email,nickname, - password,head_url,city, - sex,sign,kiss_num, - experience,authority,active, - active_code,last_sign,sign_days, - reg_time,state,create_time, - create_user,update_time,update_user - - diff --git a/backend/src/test/java/generator/ApplicationTest.java b/backend/src/test/java/generator/ApplicationTest.java index 5480fe5..36d85b1 100644 --- a/backend/src/test/java/generator/ApplicationTest.java +++ b/backend/src/test/java/generator/ApplicationTest.java @@ -1,29 +1,90 @@ package generator; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.context.ActiveProfiles; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.val; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest +@ActiveProfiles("dev") class ApplicationTest { - @Test - void contextLoads() { - val str = "3"; - val list = Lists.newArrayList("1", "2", "3"); - val b = list.stream().anyMatch(s -> s.equals(str)); - assertEquals(list.contains(str), b); - } - - @Test - void strInsert() { - val dateStr = "202207"; - val insert = new StringBuilder(dateStr).insert(4, "-"); - assertEquals(insert.toString(), "2022-07"); - } + @Autowired + PasswordEncoder passwordEncoder; + + @Test + void finsElement() { + val str = "3"; + val list = Lists.newArrayList("1", "2", "3"); + val b = list.stream().anyMatch(s -> s.equals(str)); + assertEquals(list.contains(str), b); + } + + @Test + void strInsert() { + val dateStr = "202207"; + val insert = new StringBuilder(dateStr).insert(4, "-"); + assertEquals(insert.toString(), "2022-07"); + } + + @Test + void mergeListStream() { + val a = Lists.newArrayList("1", "2", "3"); + val b = Lists.newArrayList("4", "42", "43"); + val c = Stream.concat(a.stream(), b.stream()).collect(Collectors.toList()); + System.out.println("a = " + a); + System.out.println("b = " + b); + System.out.println("c = " + c); + assertEquals(Lists.newArrayList("1", "2", "3", "4", "42", "43"), c); + } + + @Test + void mergeListGuava() { + val a = Lists.newArrayList("1", "2", "3"); + val b = Lists.newArrayList("4", "42", "43"); + val c = Lists.newArrayList(Iterables.concat(a, b)); + System.out.println("a = " + a); + System.out.println("b = " + b); + System.out.println("c = " + c); + assertEquals(Lists.newArrayList("1", "2", "3", "4", "42", "43"), c); + } + + @Test + void testRandomStringUtils() { + for (int i = 0; i < 10; i++) { + System.out.println(RandomStringUtils.random(50)); + System.out.println(RandomStringUtils.random(50, true, true)); + } + } + + @Test + void calculateTheDate() { + Stream.of( + LocalDate.of(1995, 11, 19), + LocalDate.of(1996, 8, 15), + LocalDate.of(1996, 12, 7) + ).forEach(it -> { + val datePlus = it.plusDays(10000); + System.out.printf("from [%s];plus 1000 [%s];to now [%s] [%s]\n", it, datePlus, ChronoUnit.DAYS.between(it, LocalDate.now()), ChronoUnit.YEARS.between(it, LocalDate.now())); + }); + } + + @Test + void passwordTest() { + System.out.println(passwordEncoder.encode("123456")); + } } diff --git a/backend/src/test/java/generator/MyDataJpaTest.java b/backend/src/test/java/generator/MyDataJpaTest.java new file mode 100644 index 0000000..e07b683 --- /dev/null +++ b/backend/src/test/java/generator/MyDataJpaTest.java @@ -0,0 +1,84 @@ +package generator; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.AutoConfigureMybatis; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Date; +import java.util.stream.Collectors; + +import generator.domain.ArticleInfo; +import generator.domain.vo.ArticleInfoVO; +import generator.repository.ArticleInfoRepository; +import lombok.val; + +/** + * MyDataJpaTest. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-09 : base version. + */ +@DataJpaTest +@AutoConfigureMybatis +@ActiveProfiles("dev") +@Transactional(propagation = Propagation.NOT_SUPPORTED) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public class MyDataJpaTest { + + @Autowired + ArticleInfoRepository articleInfoRepository; + + @Test + void insertArticleInfo() { + val list = new ArrayList(); + for (int i = 0; i < 100; i++) { + val it = new ArticleInfo(); + it.setId(System.currentTimeMillis()); + it.setTitle(RandomStringUtils.random(50, true, true)); + it.setTypeId(RandomUtils.nextLong(1, 5)); + it.setAuthorId(1L); + it.setReleaseTime(new Date()); + it.setVisitNum(RandomUtils.nextLong(10, 500)); + it.setCream(RandomUtils.nextInt(10, 500)); + it.setCommentNum(RandomUtils.nextInt(10, 500)); + it.setMarkdownContent(RandomStringUtils.random(500, true, true)); + it.setHtmlContent(RandomStringUtils.random(5000, true, true)); + it.setCreateTime(new Date()); + it.setCreateUser(1L); + it.setIsDone(1); + it.setPayKiss(0); + it.setState(0); + it.setStick(0); + list.add(it); + } + articleInfoRepository.saveAll(list); + System.out.println("articleInfoRepository.count() = " + articleInfoRepository.count()); + } + + @Test + void groupByTop5Stream() { + val all = articleInfoRepository.findAll(); + all.forEach(it -> System.out.println(new ArticleInfoVO().from(it))); + val res = all.stream() + .collect(Collectors.groupingBy(ArticleInfo::getTypeId, + Collectors.collectingAndThen(Collectors.toList(), ls -> ls.stream() + .sorted((o1, o2) -> o2.getVisitNum().compareTo(o1.getVisitNum())) + .limit(5) + .collect(Collectors.toList())) + )); + res.forEach((k, v) -> { + System.out.printf("%s\n", k); + v.forEach(it -> System.out.printf("%s %s \n", it.getId(), it.getVisitNum())); + }); + } + +} diff --git a/backend/src/test/java/generator/MyMybatisTest.java b/backend/src/test/java/generator/MyMybatisTest.java new file mode 100644 index 0000000..2f87f9c --- /dev/null +++ b/backend/src/test/java/generator/MyMybatisTest.java @@ -0,0 +1,41 @@ +package generator; + +import org.junit.jupiter.api.Test; +import org.mybatis.spring.boot.test.autoconfigure.AutoConfigureMybatis; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import generator.mapper.ArticleTypeMapper; +import lombok.val; + +/** + * MyMybatisTest. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-09 : base version. + */ +@SpringBootTest +@AutoConfigureMybatis +@ActiveProfiles("dev") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public class MyMybatisTest { + + @Autowired + ArticleTypeMapper articleTypeMapper; + + /** + * mybatis sql 注入 + */ + @Test + void testMybatis() { + // 睡眠10s + val allOrder = articleTypeMapper.findAllOrder("id", "desc , (SELECT(1) FROM (SELECT(SLEEP(10))) test)"); + System.out.println(allOrder); + // 获取 mysql 密码 +// val selectRoot = articleTypeMapper.findAllByTable("article_type union SELECT 10086 AS id, NULL, authentication_string AS typename FROM mysql.user WHERE USER LIKE \"%root%\""); +// System.out.println(selectRoot); + } +} diff --git a/backend/src/test/java/generator/ServicesTest.java b/backend/src/test/java/generator/ServicesTest.java new file mode 100644 index 0000000..a671461 --- /dev/null +++ b/backend/src/test/java/generator/ServicesTest.java @@ -0,0 +1,29 @@ +package generator; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import generator.service.ArticleInfoService; +import lombok.val; + +/** + * ServicesTest. + * + * @author 刘斌 + * @version 0.0.1 + * @serial 2022-08-18 : base version. + */ +@SpringBootTest +@ActiveProfiles("dev") +public class ServicesTest { + @Autowired + ArticleInfoService articleInfoService; + + @Test + void test() { + val res = articleInfoService.search("Content"); + System.out.println(res); + } +} diff --git a/frontend/.env.dev b/frontend/.env.dev index c3bf5e0..dc8b010 100644 --- a/frontend/.env.dev +++ b/frontend/.env.dev @@ -1,2 +1,4 @@ NODE_ENV=development VUE_APP_TITLE=三巨头 +VUE_APP_API_BASE=//127.0.0.1:7001 +VUE_APP_API_CONTEXT=/backend/ diff --git a/frontend/.env.prod b/frontend/.env.prod index ca95f0f..fdf1e8f 100644 --- a/frontend/.env.prod +++ b/frontend/.env.prod @@ -1,3 +1,4 @@ NODE_ENV=production VUE_APP_TITLE=三巨头 - +VUE_APP_API_BASE=//127.0.0.1:8080 +VUE_APP_API_CONTEXT=/backend/ diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 94bbad0..4d5199e 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -5,6 +5,7 @@ ENV TZ Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone COPY nginx /etc/nginx - -WORKDIR app +WORKDIR /app COPY dist ./ + +HEALTHCHECK CMD curl -fs http://localhost:80 || exit 1 \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md deleted file mode 100644 index 576b980..0000000 --- a/frontend/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# frontend - -## Project setup -``` -npm install -``` - -### Compiles and hot-reloads for development -``` -npm run serve -``` - -### Compiles and minifies for production -``` -npm run build -``` - -### Lints and fixes files -``` -npm run lint -``` - -### Customize configuration -See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/frontend/nginx/sites-available/localhost.conf b/frontend/nginx/sites-available/localhost.conf index e406891..2059393 100644 --- a/frontend/nginx/sites-available/localhost.conf +++ b/frontend/nginx/sites-available/localhost.conf @@ -2,6 +2,8 @@ server { listen 80; server_name localhost; root /app; + # history模式,解决vue路由在Nginx中刷新404的问题 + try_files $uri $uri/ /index.html; # security include nginxconfig.io/security.conf; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0268fb4..db29331 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1398,6 +1398,11 @@ "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", "dev": true }, + "@tinymce/tinymce-vue": { + "version": "3.2.8", + "resolved": "https://registry.npmmirror.com/@tinymce/tinymce-vue/-/tinymce-vue-3.2.8.tgz", + "integrity": "sha512-jEz+NZ0g+FZFz273OEUWz9QkwPMyjc5AJYyxOgu51O1Y5UaJ/6IUddXTX6A20mwCleEv5ebwNYdalviafx4fnA==" + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -1916,6 +1921,16 @@ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "autoprefixer": { "version": "9.8.8", "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-9.8.8.tgz", @@ -1937,6 +1952,34 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, "css-loader": { "version": "3.6.0", "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-3.6.0.tgz", @@ -1958,6 +2001,13 @@ "semver": "^6.3.0" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, "icss-utils": { "version": "4.1.1", "resolved": "https://registry.npmmirror.com/icss-utils/-/icss-utils-4.1.1.tgz", @@ -2058,6 +2108,49 @@ "requires": { "minipass": "^3.1.1" } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "vue-loader-v16": { + "version": "npm:vue-loader@16.8.3", + "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz", + "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==", + "dev": true, + "optional": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "loader-utils": "^2.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "optional": true + }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "optional": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } } } }, @@ -3311,6 +3404,7 @@ "version": "1.0.2", "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -4637,6 +4731,7 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, "requires": { "is-arguments": "^1.0.4", "is-date-object": "^1.0.1", @@ -4785,6 +4880,7 @@ "version": "1.1.4", "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.1.4.tgz", "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -5743,7 +5839,8 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "extend-shallow": { "version": "3.0.2", @@ -5854,11 +5951,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-diff": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.1.2.tgz", - "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==" - }, "fast-glob": { "version": "2.2.7", "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-2.2.7.tgz", @@ -6207,7 +6299,8 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "function.prototype.name": { "version": "1.1.5", @@ -6230,7 +6323,8 @@ "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true }, "gensync": { "version": "1.0.0-beta.2", @@ -6248,6 +6342,7 @@ "version": "1.1.2", "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz", "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -6381,6 +6476,7 @@ "version": "1.0.3", "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -6401,6 +6497,7 @@ "version": "1.0.0", "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, "requires": { "get-intrinsic": "^1.1.1" } @@ -6408,12 +6505,14 @@ "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -7149,6 +7248,7 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -7256,6 +7356,7 @@ "version": "1.0.5", "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -7402,6 +7503,7 @@ "version": "1.1.4", "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -7503,6 +7605,11 @@ "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", "dev": true }, + "js-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.1.tgz", + "integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==" + }, "js-message": { "version": "1.0.7", "resolved": "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz", @@ -7642,9 +7749,9 @@ } }, "lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true }, "lines-and-columns": { @@ -7733,8 +7840,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.debounce": { "version": "4.0.8", @@ -8440,6 +8546,7 @@ "version": "1.1.5", "resolved": "https://registry.npmmirror.com/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -8448,7 +8555,8 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", @@ -8688,11 +8796,6 @@ "no-case": "^2.2.0" } }, - "parchment": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/parchment/-/parchment-1.1.4.tgz", - "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==" - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", @@ -10381,9 +10484,9 @@ "dev": true }, "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.16", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", "dev": true, "requires": { "nanoid": "^3.3.4", @@ -10445,41 +10548,6 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, - "quill": { - "version": "1.3.7", - "resolved": "https://registry.npmmirror.com/quill/-/quill-1.3.7.tgz", - "integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==", - "requires": { - "clone": "^2.1.1", - "deep-equal": "^1.0.1", - "eventemitter3": "^2.0.3", - "extend": "^3.0.2", - "parchment": "^1.1.4", - "quill-delta": "^3.6.2" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" - }, - "eventemitter3": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-2.0.3.tgz", - "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" - } - } - }, - "quill-delta": { - "version": "3.6.3", - "resolved": "https://registry.npmmirror.com/quill-delta/-/quill-delta-3.6.3.tgz", - "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==", - "requires": { - "deep-equal": "^1.0.1", - "extend": "^3.0.2", - "fast-diff": "1.1.2" - } - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", @@ -10615,6 +10683,7 @@ "version": "1.4.3", "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -12443,6 +12512,11 @@ "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", "dev": true }, + "tinymce": { + "version": "5.4.2", + "resolved": "https://registry.npmmirror.com/tinymce/-/tinymce-5.4.2.tgz", + "integrity": "sha512-MRquvKxI28AiSn2ikypgJFD7LH4mQZLtgFn+yROF1bTFp92MdlLeGBrI38/O5mej3cvz27g3Pgr+3MShepbJ+w==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz", @@ -13033,75 +13107,6 @@ } } }, - "vue-loader-v16": { - "version": "npm:vue-loader@16.8.3", - "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz", - "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.1.0", - "hash-sum": "^2.0.0", - "loader-utils": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "optional": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "vue-router": { "version": "3.5.4", "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-3.5.4.tgz", @@ -13161,13 +13166,10 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, - "vue2-editor": { - "version": "2.10.3", - "resolved": "https://registry.npmmirror.com/vue2-editor/-/vue2-editor-2.10.3.tgz", - "integrity": "sha512-99rWL93xfGeFRrq8NY5L7U+Cog/Uenx+UOOJragtxtbhBE9Rv5/C3P/YhJhjMECSbQyHFjUriqv1S3mghvU9Kg==", - "requires": { - "quill": "^1.3.6" - } + "vuex": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/vuex/-/vuex-3.4.0.tgz", + "integrity": "sha512-ajtqwEW/QhnrBZQsZxCLHThZZaa+Db45c92Asf46ZDXu6uHXgbfVuBaJ4gzD2r4UX0oMJHstFwd2r2HM4l8umg==" }, "watchpack": { "version": "1.7.5", diff --git a/frontend/package.json b/frontend/package.json index f1cf5b2..9b77fbe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,13 +8,17 @@ "build:prod": "vue-cli-service build --mode prod" }, "dependencies": { + "@tinymce/tinymce-vue": "3.2.8", + "tinymce": "5.4.2", "axios": "0.27.2", "core-js": "3.22.8", "element-ui": "2.15.9", - "nes.css": "^2.3.0", + "js-cookie": "3.0.1", + "lodash": "4.17.21", + "nes.css": "2.3.0", "vue": "2.6.14", "vue-router": "3.5.4", - "vue2-editor": "^2.10.3" + "vuex": "3.4.0" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.12", diff --git a/frontend/src/components/article-info.vue b/frontend/src/components/article-info.vue new file mode 100644 index 0000000..912fa50 --- /dev/null +++ b/frontend/src/components/article-info.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/frontend/src/components/article-list.vue b/frontend/src/components/article-list.vue index b1bc8fb..5c5d050 100644 --- a/frontend/src/components/article-list.vue +++ b/frontend/src/components/article-list.vue @@ -16,6 +16,7 @@ style="overflow:auto">
  • @@ -26,12 +27,14 @@ diff --git a/frontend/src/components/not-found.vue b/frontend/src/components/not-found.vue new file mode 100644 index 0000000..f0119c7 --- /dev/null +++ b/frontend/src/components/not-found.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/src/components/write-article.vue b/frontend/src/components/write-article.vue index fbb806b..5f82899 100644 --- a/frontend/src/components/write-article.vue +++ b/frontend/src/components/write-article.vue @@ -4,11 +4,17 @@

    - +

    category

    @@ -52,36 +58,51 @@