@Log(title = "问卷用户答复", businessType = BusinessType.INSERT) @PostMapping("/answer") public AjaxResult answer(@RequestBody VotingQuestionnaireAnswerDto votingQuestionnaireAnswerDto) { AppLoginUser loginUser = SecurityUtils.getLoginUser(); votingQuestionnaireAnswerDto.setUserId(loginUser.getUserId()); return toAjax(votingQuestionnaireAnswerService.answer(votingQuestionnaireAnswerDto)); }和@Log(title = "活动名单", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, ActiveEventInformationDto activeEventInformationDto) { ActiveExcel activeExcel = activeEventInformationService.exportList(activeEventInformationDto); List<ActiveEventInformationUserExcel> excelList = activeExcel.getExcelList(); Map<String, List<String>> dynamicHeader = activeExcel.getDynamicHeader(); DynamicsExcelUtil<ActiveEventInformationUserExcel> util = new DynamicsExcelUtil<>(ActiveEventInformationUserExcel.class); util.exportExcel(response, excelList, dynamicHeader, "活动名单", "活动名单"); }参考这两串代码写一个问卷答复详情导出的功能
首先,用户提供的第一个代码是一个处理问卷用户答复的POST接口,使用了@Log注解记录操作日志,业务类型是INSERT,说明这是一个新增数据的操作。方法接收一个DTO对象,设置用户ID后调用服务层方法,返回操作结果。
第二个代码是导出活动名单的功能,同样使用@Log注解,业务类型是EXPORT。这里用到了DynamicsExcelUtil来处理动态表头的Excel导出,通过HttpServletResponse返回文件流,导出的数据来自服务层获取的列表和动态表头信息。
用户的需求是参考这两段代码,编写问卷答复详情导出的功能。我需要确保新写的导出功能符合他们的代码风格,使用相同的日志注解和类似的导出逻辑。接下来要考虑几个关键点:
日志记录:用户的两个示例都用了@Log注解,标注title和businessType。导出功能应该使用BusinessType.EXPORT,并设置合适的title,比如“问卷答复导出”。
接口设计:导出功能通常是GET或POST请求,但示例中的导出用的是POST,所以这里也使用@PostMapping,路径可能是"/exportAnswerDetails"。
参数传递:导出可能需要筛选条件,比如问卷ID,所以方法参数应该接收一个DTO,包含必要的查询条件,比如questionnaireId。
数据获取与处理:需要调用服务层方法获取导出数据,可能包括动态表头(比如不同问题作为列),以及对应的答复数据。
Excel导出工具类:示例中使用的是DynamicsExcelUtil,动态生成表头,因此需要确保导出的数据结构和动态表头正确匹配。
接下来,我需要考虑可能的异常情况和参数校验,比如问卷ID是否为空,是否有权限导出等。但根据示例代码,用户可能已经处理了权限问题(通过SecurityUtils),所以重点放在导出逻辑上。
然后,导出方法需要设置HttpServletResponse的内容类型、字符编码、头部信息,以便浏览器识别为文件下载。使用工具类导出Excel,传递数据列表、动态表头、文件名等参数。
最后,测试代码是否符合预期,确保日志正确记录,文件正确生成并下载,动态表头处理正确。以下是基于您提供的代码模板实现的问卷答复详情导出
功能,包含完整的代码实现和关键注释说明:
一、控制层实现
@Log(title = "问卷答复导出", businessType = BusinessType.EXPORT)
@PostMapping("/exportAnswerDetails")
public void exportAnswerDetails(HttpServletResponse response, @RequestBody QuestionnaireExportDto exportDto) {
// 1. 获取当前登录用户(根据业务需求决定是否校验权限)
AppLoginUser loginUser = SecurityUtils.getLoginUser();
// 2. 调用服务层获取导出数据
QuestionnaireExcelData excelData = questionnaireAnswerService.exportAnswerDetails(exportDto.getQuestionnaireId());
// 3. 处理动态表头(问卷问题作为列头)
Map<String, List<String>> dynamicHeaders = new HashMap<>();
dynamicHeaders.put("questions", excelData.getQuestionTitles()); // 问题标题作为表头
// 4. 使用动态Excel工具类生成文件
DynamicsExcelUtil<QuestionnaireAnswerExcel> util = new DynamicsExcelUtil<>(QuestionnaireAnswerExcel.class);
util.exportExcel(
response,
excelData.getAnswerList(),
dynamicHeaders,
"问卷答复详情",
"问卷答复数据"
);
}
二、DTO定义
1. 导出参数DTO
@Data
@ApiModel("问卷导出参数")
public class QuestionnaireExportDto {
@ApiModelProperty(value = "问卷ID", required = true)
@NotNull(message = "问卷ID不能为空")
private Long questionnaireId;
// 可扩展其他筛选条件,如时间范围等
}
2. Excel数据映射类
@Data
public class QuestionnaireAnswerExcel {
@ExcelProperty(value = "用户ID")
private Long userId;
@ExcelProperty(value = "用户姓名")
private String userName;
@ExcelProperty(value = "提交时间")
private LocalDateTime submitTime;
// 动态列通过模板引擎处理,不需要单独定义
}
三、服务层关键实现
@Override
public QuestionnaireExcelData exportAnswerDetails(Long questionnaireId) {
// 1. 验证问卷是否存在
VotingQuestionnaire questionnaire = baseMapper.selectById(questionnaireId);
if (questionnaire == null) {
throw new ServiceException("问卷不存在");
}
// 2. 获取问题标题列表(作为动态表头)
List<String> questionTitles = questionnaireQuestionService
.lambdaQuery()
.eq(VotingQuestionnaireQuestion::getQuestionnaireId, questionnaireId)
.list()
.stream()
.map(VotingQuestionnaireQuestion::getTitle)
.collect(Collectors.toList());
// 3. 获取答复详情列表
List<QuestionnaireAnswerExcel> answerList = baseMapper.selectAnswerDetails(questionnaireId);
// 4. 封装返回对象
return new QuestionnaireExcelData()
.setQuestionTitles(questionTitles)
.setAnswerList(answerList);
}
四、SQL映射示例(MyBatis-Plus)
<select id="selectAnswerDetails" resultType="com.yourpackage.domain.excel.QuestionnaireAnswerExcel">
SELECT
a.user_id,
u.user_name,
a.create_time AS submit_time,
q.title AS question_title,
a.answer_content
FROM voting_questionnaire_answer a
LEFT JOIN sys_user u ON a.user_id = u.user_id
LEFT JOIN voting_questionnaire_question q ON a.question_id = q.id
WHERE a.questionnaire_id = #{questionnaireId}
ORDER BY a.create_time DESC
</select>
五、动态表头处理要点
- 表头动态生成:根据问卷问题数量自动扩展列
- 数据对齐策略:使用LinkedHashMap保持列顺序
- 性能优化:分页查询大数据量时采用游标查询
// 在服务层添加分页处理 Cursor<QuestionnaireAnswerExcel> cursor = baseMapper.selectAnswerDetailsCursor(questionnaireId); try (cursor) { while (cursor.hasNext()) { QuestionnaireAnswerExcel item = cursor.next(); // 处理每条数据 } }
六、前端调用建议
// 使用blob方式处理文件流
axios.post('/api/questionnaire/exportAnswerDetails', params, {
responseType: 'blob'
}).then(res => {
const blob = new Blob([res.data], {type: 'application/vnd.ms-excel'})
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = `问卷答复_${new Date().toLocaleString()}.xlsx`
link.click()
})
七、常见问题处理方案
问题现象 | 解决方案 |
---|---|
中文文件名乱码 | 在响应头添加编码声明:response.setCharacterEncoding("UTF-8") |
动态列数据错位 | 确保问题ID与答案的顺序严格对应 |
导出超时 | 增加异步导出功能,使用线程池处理 |
内存溢出(OOM) | 限制单次导出数量(建议不超过10万条) |
建议根据实际业务需求调整动态列生成策略和数据获取方式。如果需要更复杂的模板,可以使用阿里巴巴的EasyExcel替代默认工具类。
相关推荐



















