feat: grade new product survey step one

main
chenyuan 3 weeks ago
parent 0e354b3abb
commit 90018ba287

@ -0,0 +1,36 @@
package com.sztzjy.linkCommerce.entity.dto;
import java.util.List;
public class NewProductSurveyStepOneCheckRequest {
private List<Item> items;
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public static class Item {
private String id;
private String category;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
}

@ -0,0 +1,73 @@
package com.sztzjy.linkCommerce.entity.dto;
import java.util.ArrayList;
import java.util.List;
public class NewProductSurveyStepOneCheckResult {
private List<ItemResult> items = new ArrayList<>();
private int correctCount;
private int totalCount;
private boolean allCorrect;
public List<ItemResult> getItems() {
return items;
}
public void setItems(List<ItemResult> items) {
this.items = items;
}
public int getCorrectCount() {
return correctCount;
}
public void setCorrectCount(int correctCount) {
this.correctCount = correctCount;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public boolean isAllCorrect() {
return allCorrect;
}
public void setAllCorrect(boolean allCorrect) {
this.allCorrect = allCorrect;
}
public static class ItemResult {
private String id;
private boolean correct;
private String message;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public boolean isCorrect() {
return correct;
}
public void setCorrect(boolean correct) {
this.correct = correct;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}

@ -0,0 +1,9 @@
package com.sztzjy.linkCommerce.service;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckResult;
public interface NewProductSurveyStepOneService {
NewProductSurveyStepOneCheckResult check(NewProductSurveyStepOneCheckRequest request, JwtUser user);
}

@ -0,0 +1,143 @@
package com.sztzjy.linkCommerce.service.impl;
import com.alibaba.fastjson.JSON;
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckResult;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service
public class NewProductSurveyStepOneServiceImpl implements NewProductSurveyStepOneService {
private static final String TASK_KEY = "new-product-survey";
private static final int STEP_NO = 1;
private static final String CORRECT_MESSAGE = "分类正确";
private static final String INCORRECT_MESSAGE = "分类有误,请重新选择";
private static final Set<String> ALLOWED_CATEGORIES = new LinkedHashSet<>(Arrays.asList("核心层", "有形层", "延伸层"));
private static final Map<String, String> DEFAULT_ANSWERS = createDefaultAnswers();
private final JdbcTemplate jdbcTemplate;
@Autowired
public NewProductSurveyStepOneServiceImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@PostConstruct
public void initializeStandardAnswers() {
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS training_step_standard_answer ("
+ "id varchar(64) NOT NULL COMMENT 'primary id',"
+ "task_key varchar(128) NOT NULL COMMENT 'training task key',"
+ "step_no int NOT NULL COMMENT 'step number',"
+ "answer_json longtext NOT NULL COMMENT 'standard answer json',"
+ "create_time datetime NULL COMMENT 'create time',"
+ "update_time datetime NULL COMMENT 'update time',"
+ "PRIMARY KEY (id),"
+ "UNIQUE KEY uk_training_step_standard_answer (task_key, step_no)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='training step standard answer'");
jdbcTemplate.update("INSERT IGNORE INTO training_step_standard_answer "
+ "(id, task_key, step_no, answer_json, create_time, update_time) VALUES (?, ?, ?, ?, NOW(), NOW())",
"new-product-survey-step-1", TASK_KEY, STEP_NO, JSON.toJSONString(DEFAULT_ANSWERS));
}
@Override
public NewProductSurveyStepOneCheckResult check(NewProductSurveyStepOneCheckRequest request, JwtUser user) {
requireStudent(user);
Map<String, String> submitted = validateSubmittedItems(request == null ? null : request.getItems());
Map<String, String> standardAnswers = loadStandardAnswers();
NewProductSurveyStepOneCheckResult result = new NewProductSurveyStepOneCheckResult();
int correctCount = 0;
for (String id : standardAnswers.keySet()) {
boolean correct = standardAnswers.get(id).equals(submitted.get(id));
NewProductSurveyStepOneCheckResult.ItemResult itemResult = new NewProductSurveyStepOneCheckResult.ItemResult();
itemResult.setId(id);
itemResult.setCorrect(correct);
itemResult.setMessage(correct ? CORRECT_MESSAGE : INCORRECT_MESSAGE);
result.getItems().add(itemResult);
if (correct) {
correctCount++;
}
}
result.setCorrectCount(correctCount);
result.setTotalCount(standardAnswers.size());
result.setAllCorrect(correctCount == standardAnswers.size());
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 Map<String, String> validateSubmittedItems(List<NewProductSurveyStepOneCheckRequest.Item> items) {
if (items == null || items.size() != DEFAULT_ANSWERS.size()) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请完成全部卖点分类后再判题");
}
Map<String, String> submitted = new LinkedHashMap<>();
for (NewProductSurveyStepOneCheckRequest.Item item : items) {
String id = item == null ? null : StringUtils.trimToEmpty(item.getId());
String category = item == null ? null : StringUtils.trimToEmpty(item.getCategory());
if (!DEFAULT_ANSWERS.containsKey(id) || !ALLOWED_CATEGORIES.contains(category) || submitted.put(id, category) != null) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "提交的卖点分类数据不合法");
}
}
if (!submitted.keySet().equals(DEFAULT_ANSWERS.keySet())) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "提交的卖点分类数据不完整");
}
return submitted;
}
@SuppressWarnings("unchecked")
private Map<String, String> loadStandardAnswers() {
String answerJson = jdbcTemplate.queryForObject(
"SELECT answer_json FROM training_step_standard_answer WHERE task_key = ? AND step_no = ?",
String.class, TASK_KEY, STEP_NO);
Map<String, Object> raw = JSON.parseObject(answerJson, LinkedHashMap.class);
Map<String, String> answers = new LinkedHashMap<>();
for (String id : DEFAULT_ANSWERS.keySet()) {
Object category = raw == null ? null : raw.get(id);
if (category == null || !ALLOWED_CATEGORIES.contains(String.valueOf(category))) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, "第一步标准答案未正确配置");
}
answers.put(id, String.valueOf(category));
}
if (raw == null || raw.size() != answers.size()) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, "第一步标准答案未正确配置");
}
return answers;
}
private static Map<String, String> createDefaultAnswers() {
Map<String, String> answers = new LinkedHashMap<>();
answers.put("selling-point-1", "核心层");
answers.put("selling-point-2", "有形层");
answers.put("selling-point-3", "核心层");
answers.put("selling-point-4", "核心层");
answers.put("selling-point-5", "有形层");
answers.put("selling-point-6", "有形层");
answers.put("selling-point-7", "有形层");
answers.put("selling-point-8", "延伸层");
answers.put("selling-point-9", "延伸层");
answers.put("selling-point-10", "延伸层");
answers.put("selling-point-11", "有形层");
return answers;
}
}

@ -0,0 +1,114 @@
package com.sztzjy.linkCommerce.service.impl;
import com.alibaba.fastjson.JSON;
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckResult;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class NewProductSurveyStepOneServiceImplTest {
@Test
void checkReturnsPerItemFeedbackWithoutExposingCorrectCategories() {
JdbcTemplate jdbcTemplate = standardAnswerJdbcTemplate();
NewProductSurveyStepOneServiceImpl service = new NewProductSurveyStepOneServiceImpl(jdbcTemplate);
NewProductSurveyStepOneCheckResult result = service.check(requestWithSecondCategory("核心层"), student());
assertEquals(10, result.getCorrectCount());
assertEquals(11, result.getTotalCount());
assertFalse(result.isAllCorrect());
assertTrue(result.getItems().get(0).isCorrect());
assertFalse(result.getItems().get(1).isCorrect());
assertEquals("分类有误,请重新选择", result.getItems().get(1).getMessage());
assertFalse(JSON.toJSONString(result).contains("correctCategory"));
}
@Test
void checkRejectsIncompleteAnswersInvalidCategoriesAndNonStudents() {
NewProductSurveyStepOneServiceImpl service = new NewProductSurveyStepOneServiceImpl(standardAnswerJdbcTemplate());
assertThrows(ServiceException.class, () -> service.check(request(Arrays.asList(item("selling-point-1", "核心层"))), student()));
assertThrows(ServiceException.class, () -> service.check(requestWithSecondCategory("错误层级"), student()));
assertThrows(ServiceException.class, () -> service.check(requestWithSecondCategory("有形层"), teacher()));
}
@Test
void initializationCreatesTheTableAndDoesNotOverwriteExistingAnswers() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
NewProductSurveyStepOneServiceImpl service = new NewProductSurveyStepOneServiceImpl(jdbcTemplate);
service.initializeStandardAnswers();
verify(jdbcTemplate).execute(contains("CREATE TABLE IF NOT EXISTS training_step_standard_answer"));
verify(jdbcTemplate).update(startsWith("INSERT IGNORE INTO training_step_standard_answer"), any(), any(), any(), any());
}
private JdbcTemplate standardAnswerJdbcTemplate() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
Map<String, String> answers = new LinkedHashMap<>();
for (NewProductSurveyStepOneCheckRequest.Item item : defaultAnswers()) {
answers.put(item.getId(), item.getCategory());
}
when(jdbcTemplate.queryForObject(any(String.class), any(Class.class), any(), any())).thenReturn(JSON.toJSONString(answers));
return jdbcTemplate;
}
private List<NewProductSurveyStepOneCheckRequest.Item> defaultAnswers() {
return Arrays.asList(
item("selling-point-1", "核心层"), item("selling-point-2", "有形层"), item("selling-point-3", "核心层"),
item("selling-point-4", "核心层"), item("selling-point-5", "有形层"), item("selling-point-6", "有形层"),
item("selling-point-7", "有形层"), item("selling-point-8", "延伸层"), item("selling-point-9", "延伸层"),
item("selling-point-10", "延伸层"), item("selling-point-11", "有形层"));
}
private NewProductSurveyStepOneCheckRequest requestWithSecondCategory(String category) {
List<NewProductSurveyStepOneCheckRequest.Item> items = defaultAnswers();
items.get(1).setCategory(category);
return request(items);
}
private NewProductSurveyStepOneCheckRequest request(List<NewProductSurveyStepOneCheckRequest.Item> items) {
NewProductSurveyStepOneCheckRequest request = new NewProductSurveyStepOneCheckRequest();
request.setItems(items);
return request;
}
private NewProductSurveyStepOneCheckRequest.Item item(String id, String category) {
NewProductSurveyStepOneCheckRequest.Item item = new NewProductSurveyStepOneCheckRequest.Item();
item.setId(id);
item.setCategory(category);
return item;
}
private JwtUser student() {
JwtUser user = new JwtUser();
user.setUserId("stu-1");
user.setRoleId(4);
return user;
}
private JwtUser teacher() {
JwtUser user = student();
user.setRoleId(3);
return user;
}
}
Loading…
Cancel
Save