diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationRequest.java new file mode 100644 index 0000000..b2b6da0 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationRequest.java @@ -0,0 +1,23 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ProductDevelopmentFactorsStepOneValidationRequest { + private List factors; + + public List getFactors() { return factors; } + public void setFactors(List factors) { this.factors = factors; } + + public static class Row { + private String dimension; + private String successAnalysis; + private String failedAnalysis; + + public String getDimension() { return dimension; } + public void setDimension(String dimension) { this.dimension = dimension; } + public String getSuccessAnalysis() { return successAnalysis; } + public void setSuccessAnalysis(String successAnalysis) { this.successAnalysis = successAnalysis; } + public String getFailedAnalysis() { return failedAnalysis; } + public void setFailedAnalysis(String failedAnalysis) { this.failedAnalysis = failedAnalysis; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationResult.java new file mode 100644 index 0000000..446d0fb --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ProductDevelopmentFactorsStepOneValidationResult { + private boolean valid; + private String message; + + public boolean isValid() { return valid; } + public void setValid(boolean valid) { this.valid = valid; } + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepOneService.java b/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepOneService.java new file mode 100644 index 0000000..cb5e23c --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepOneService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepOneValidationResult; + +public interface ProductDevelopmentFactorsStepOneService { + ProductDevelopmentFactorsStepOneValidationResult validate(ProductDevelopmentFactorsStepOneValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImpl.java new file mode 100644 index 0000000..9aaa939 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImpl.java @@ -0,0 +1,61 @@ +package com.sztzjy.linkCommerce.service.impl; + +import com.sztzjy.linkCommerce.config.exception.handler.ServiceException; +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepOneValidationResult; +import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepOneService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +@Service +public class ProductDevelopmentFactorsStepOneServiceImpl implements ProductDevelopmentFactorsStepOneService { + private static final Set DIMENSIONS = new LinkedHashSet<>(Arrays.asList( + "用户需求真实性", "产品体验闭环", "生态与兼容")); + + @Override + public ProductDevelopmentFactorsStepOneValidationResult validate(ProductDevelopmentFactorsStepOneValidationRequest request, JwtUser user) { + requireStudent(user); + if (request == null || request.getFactors() == null || request.getFactors().size() != DIMENSIONS.size()) { + throw badRequest("请完成用户需求真实性、产品体验闭环和生态与兼容分析"); + } + Set submittedDimensions = new LinkedHashSet<>(); + for (ProductDevelopmentFactorsStepOneValidationRequest.Row row : request.getFactors()) { + String dimension = row == null ? "" : StringUtils.trimToEmpty(row.getDimension()); + if (!DIMENSIONS.contains(dimension) || !submittedDimensions.add(dimension)) { + throw badRequest("提交的分析维度不完整或重复"); + } + if (!StringUtils.isNotBlank(row.getSuccessAnalysis())) { + throw badRequest("请填写" + dimension + "的成功产品分析"); + } + if (!StringUtils.isNotBlank(row.getFailedAnalysis())) { + throw badRequest("请填写" + dimension + "的失败产品分析"); + } + } + if (!submittedDimensions.equals(DIMENSIONS)) { + throw badRequest("请完成用户需求真实性、产品体验闭环和生态与兼容分析"); + } + ProductDevelopmentFactorsStepOneValidationResult result = new ProductDevelopmentFactorsStepOneValidationResult(); + result.setValid(true); + result.setMessage("校验通过"); + return result; + } + + private void requireStudent(JwtUser user) { + if (user == null || StringUtils.isBlank(user.getUserId())) { + throw new ServiceException(HttpStatus.UNAUTHORIZED, "请先登录后再提交"); + } + if (user.getRoleId() != 4) { + throw new ServiceException(HttpStatus.FORBIDDEN, "仅学生可提交实训答案"); + } + } + + private ServiceException badRequest(String message) { + return new ServiceException(HttpStatus.BAD_REQUEST, message); + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImplTest.java new file mode 100644 index 0000000..85a8506 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImplTest.java @@ -0,0 +1,79 @@ +package com.sztzjy.linkCommerce.service.impl; + +import com.sztzjy.linkCommerce.config.exception.handler.ServiceException; +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepOneValidationResult; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ProductDevelopmentFactorsStepOneServiceImplTest { + + @Test + void acceptsStudentWithAllThreeCompleteFactorAnalyses() { + ProductDevelopmentFactorsStepOneServiceImpl service = new ProductDevelopmentFactorsStepOneServiceImpl(); + + ProductDevelopmentFactorsStepOneValidationResult result = service.validate(validRequest(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsBlankOrForgedFactorAnalyses() { + ProductDevelopmentFactorsStepOneServiceImpl service = new ProductDevelopmentFactorsStepOneServiceImpl(); + + ProductDevelopmentFactorsStepOneValidationRequest blankAnalysis = validRequest(); + blankAnalysis.getFactors().get(1).setFailedAnalysis(" "); + assertThrows(ServiceException.class, () -> service.validate(blankAnalysis, student())); + + ProductDevelopmentFactorsStepOneValidationRequest duplicateDimension = validRequest(); + duplicateDimension.getFactors().get(2).setDimension("用户需求真实性"); + assertThrows(ServiceException.class, () -> service.validate(duplicateDimension, student())); + + ProductDevelopmentFactorsStepOneValidationRequest forgedDimension = validRequest(); + forgedDimension.getFactors().get(2).setDimension("技术应用"); + assertThrows(ServiceException.class, () -> service.validate(forgedDimension, student())); + } + + @Test + void rejectsNonStudent() { + ProductDevelopmentFactorsStepOneServiceImpl service = new ProductDevelopmentFactorsStepOneServiceImpl(); + + assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher())); + } + + private ProductDevelopmentFactorsStepOneValidationRequest validRequest() { + ProductDevelopmentFactorsStepOneValidationRequest request = new ProductDevelopmentFactorsStepOneValidationRequest(); + request.setFactors(Arrays.asList( + row("用户需求真实性", "解决高频付费痛点", "没有真实需求"), + row("产品体验闭环", "操作简单且反馈明确", "操作复杂且不稳定"), + row("生态与兼容", "兼容主流生态", "无法接入平台"))); + return request; + } + + private ProductDevelopmentFactorsStepOneValidationRequest.Row row(String dimension, String successAnalysis, String failedAnalysis) { + ProductDevelopmentFactorsStepOneValidationRequest.Row row = new ProductDevelopmentFactorsStepOneValidationRequest.Row(); + row.setDimension(dimension); + row.setSuccessAnalysis(successAnalysis); + row.setFailedAnalysis(failedAnalysis); + return row; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("stu-1"); + user.setRoleId(4); + return user; + } + + private JwtUser teacher() { + JwtUser user = new JwtUser(); + user.setUserId("teacher-1"); + user.setRoleId(2); + return user; + } +}