From 1e409dfa69d7053a5b2e8de50909f9bf95538b65 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Tue, 11 Aug 2026 18:45:36 +0800 Subject: [PATCH] feat: validate consumer behavior kano needs --- .../stu/StudentTrainingAnswerController.java | 17 +++++ ...sumerBehaviorStepTwoValidationRequest.java | 23 ++++++ ...nsumerBehaviorStepTwoValidationResult.java | 11 +++ .../ConsumerBehaviorStepTwoService.java | 9 +++ .../ConsumerBehaviorStepTwoServiceImpl.java | 54 +++++++++++++ ...onsumerBehaviorStepTwoServiceImplTest.java | 75 +++++++++++++++++++ 6 files changed, 189 insertions(+) create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepTwoService.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java create mode 100644 src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImplTest.java diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java index c6dbeef..dc859bd 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java @@ -30,6 +30,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValid import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationResult; import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepTwoService; @@ -43,6 +45,7 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepFourService; import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepOneService; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepTwoService; import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.util.ResultEntity; import io.swagger.annotations.Api; @@ -97,6 +100,9 @@ public class StudentTrainingAnswerController { @Autowired private ConsumerBehaviorStepOneService consumerBehaviorStepOneService; + @Autowired + private ConsumerBehaviorStepTwoService consumerBehaviorStepTwoService; + @GetMapping("/{taskKey}") @ApiOperation("查询当前学生指定实训任务答案") public ResultEntity detail(@PathVariable String taskKey, @@ -268,6 +274,17 @@ public class StudentTrainingAnswerController { } } + @PostMapping("/consumer-behavior/step-2/validate") + @ApiOperation("消费者需求与行为第二步校验") + public ResultEntity validateConsumerBehaviorStepTwo( + @RequestBody ConsumerBehaviorStepTwoValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", consumerBehaviorStepTwoService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + @DeleteMapping("/{taskKey}") @ApiOperation("删除当前学生指定实训任务答案") public ResultEntity delete(@PathVariable String taskKey, diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java new file mode 100644 index 0000000..bb2d24e --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java @@ -0,0 +1,23 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ConsumerBehaviorStepTwoValidationRequest { + private List needs; + + public List getNeeds() { return needs; } + public void setNeeds(List needs) { this.needs = needs; } + + public static class KanoNeed { + private String feature; + private String kanoType; + private String featureDirection; + + public String getFeature() { return feature; } + public void setFeature(String feature) { this.feature = feature; } + public String getKanoType() { return kanoType; } + public void setKanoType(String kanoType) { this.kanoType = kanoType; } + public String getFeatureDirection() { return featureDirection; } + public void setFeatureDirection(String featureDirection) { this.featureDirection = featureDirection; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java new file mode 100644 index 0000000..e34f7e4 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerBehaviorStepTwoValidationResult { + 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/ConsumerBehaviorStepTwoService.java b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepTwoService.java new file mode 100644 index 0000000..3c8cadf --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepTwoService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; + +public interface ConsumerBehaviorStepTwoService { + ConsumerBehaviorStepTwoValidationResult validate(ConsumerBehaviorStepTwoValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java new file mode 100644 index 0000000..78dd7cc --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java @@ -0,0 +1,54 @@ +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.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepTwoService; +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 ConsumerBehaviorStepTwoServiceImpl implements ConsumerBehaviorStepTwoService { + private static final int MAX_NEED_COUNT = 20; + private static final Set KANO_TYPES = new LinkedHashSet<>(Arrays.asList("基本型", "期望型", "兴奋型", "无差异型", "反向型")); + + @Override + public ConsumerBehaviorStepTwoValidationResult validate(ConsumerBehaviorStepTwoValidationRequest request, JwtUser user) { + requireStudent(user); + if (request == null || request.getNeeds() == null || request.getNeeds().isEmpty()) { + throw badRequest("请至少填写一项KANO需求分类"); + } + if (request.getNeeds().size() > MAX_NEED_COUNT) { + throw badRequest("KANO需求分类最多填写20行"); + } + for (ConsumerBehaviorStepTwoValidationRequest.KanoNeed need : request.getNeeds()) { + if (need == null || StringUtils.isBlank(need.getFeature()) + || StringUtils.isBlank(need.getFeatureDirection()) || !KANO_TYPES.contains(StringUtils.trimToEmpty(need.getKanoType()))) { + throw badRequest("请完整填写功能、KANO类型和对应功能方向"); + } + } + ConsumerBehaviorStepTwoValidationResult result = new ConsumerBehaviorStepTwoValidationResult(); + 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/ConsumerBehaviorStepTwoServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImplTest.java new file mode 100644 index 0000000..51a2ef6 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImplTest.java @@ -0,0 +1,75 @@ +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.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ConsumerBehaviorStepTwoServiceImplTest { + + @Test + void acceptsCompleteKanoNeedsForStudent() { + ConsumerBehaviorStepTwoServiceImpl service = new ConsumerBehaviorStepTwoServiceImpl(); + + ConsumerBehaviorStepTwoValidationResult result = service.validate(validRequest(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsInvalidKanoTypeAndMoreThanTwentyRows() { + ConsumerBehaviorStepTwoServiceImpl service = new ConsumerBehaviorStepTwoServiceImpl(); + ConsumerBehaviorStepTwoValidationRequest invalidType = validRequest(); + invalidType.getNeeds().get(0).setKanoType("未知类型"); + assertThrows(ServiceException.class, () -> service.validate(invalidType, student())); + + ConsumerBehaviorStepTwoValidationRequest tooMany = new ConsumerBehaviorStepTwoValidationRequest(); + tooMany.setNeeds(Collections.nCopies(21, row("功能", "基本型", "功能方向"))); + assertThrows(ServiceException.class, () -> service.validate(tooMany, student())); + } + + @Test + void rejectsNonStudent() { + ConsumerBehaviorStepTwoServiceImpl service = new ConsumerBehaviorStepTwoServiceImpl(); + + assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher())); + } + + private ConsumerBehaviorStepTwoValidationRequest validRequest() { + ConsumerBehaviorStepTwoValidationRequest request = new ConsumerBehaviorStepTwoValidationRequest(); + request.setNeeds(Arrays.asList( + row("灯光亮度可无级调节", "期望型", "照明系统"), + row("根据时间自动调节灯光", "兴奋型", "智能场景"), + row("白噪声可定时关闭", "基本型", "音频系统"))); + return request; + } + + private ConsumerBehaviorStepTwoValidationRequest.KanoNeed row(String feature, String kanoType, String featureDirection) { + ConsumerBehaviorStepTwoValidationRequest.KanoNeed row = new ConsumerBehaviorStepTwoValidationRequest.KanoNeed(); + row.setFeature(feature); + row.setKanoType(kanoType); + row.setFeatureDirection(featureDirection); + 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; + } +}