From 9b4859447974be6658e91c65637d313cd342a6a8 Mon Sep 17 00:00:00 2001 From: mirage <1127314491@qq.com> Date: Tue, 24 Feb 2026 15:26:34 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0:=201.=20?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E8=8E=B7=E5=8F=96=E6=95=99=E5=B8=88=E4=BA=8C?= =?UTF-8?q?=E7=BB=B4=E7=A0=81=E7=9A=84=E5=8A=9F=E8=83=BD(=E5=89=8D?= =?UTF-8?q?=E7=AB=AF+=E5=90=8E=E7=AB=AF)=202.=20=E5=AD=A6=E7=94=9F?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E7=B1=BB=E5=8A=A0=E4=B8=80=E4=BA=9B=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/src/api/teacher.ts | 18 + admin/src/utils/request/axios.ts | 5 +- .../admin/controller/TeacherController.java | 39 +- .../mdd/admin/service/ITeacherService.java | 28 +- .../service/impl/StudentInfoServiceImpl.java | 19 +- .../service/impl/TeacherServiceImpl.java | 404 +++++++++++++++--- .../service/impl/TeachingTaskServiceImpl.java | 12 +- .../validate/StudentInfoSearchValidate.java | 6 + .../teacher/TeacherCreateValidate.java | 6 +- .../teacher/TeacherSearchValidate.java | 6 +- .../teacher/TeacherUpdateValidate.java | 13 +- .../com/mdd/admin/vo/StudentInfoListedVo.java | 13 + .../mdd/admin/vo/teacher/TeacherDetailVo.java | 12 +- .../mdd/admin/vo/teacher/TeacherListedVo.java | 13 +- .../java/com/mdd/common/entity/Teacher.java | 24 +- .../java/com/mdd/common/util/QrCodeUtil.java | 96 +++++ 16 files changed, 612 insertions(+), 102 deletions(-) create mode 100644 server/like-common/src/main/java/com/mdd/common/util/QrCodeUtil.java diff --git a/admin/src/api/teacher.ts b/admin/src/api/teacher.ts index cfe55bc2..6739f2f1 100644 --- a/admin/src/api/teacher.ts +++ b/admin/src/api/teacher.ts @@ -49,3 +49,21 @@ export function teacherConfigRole(params: Record) { export function teacherGetConfig() { return request.get({ url: '/teacher/get.config' }) } + +// 生成邀请码和二维码 +export function teacherGenerateInvitationCode(params: Record) { + return request.post({ url: '/teacher/generateInvitationCode', params }) +} + +// 获取教师二维码图片URL +export function teacherGetQrCodeUrl(params: Record) { + return request.get({ url: '/teacher/qrcode', params }) +} + +// 获取教师二维码图片流(带鉴权,用于展示与下载) +export function teacherGetQrCodeImage(params: Record) { + return request.get( + { url: '/teacher/qrcode/image', params, responseType: 'blob' }, + { isReturnDefaultResponse: true } + ) +} diff --git a/admin/src/utils/request/axios.ts b/admin/src/utils/request/axios.ts index d60a2d33..5dc2ee6f 100644 --- a/admin/src/utils/request/axios.ts +++ b/admin/src/utils/request/axios.ts @@ -149,8 +149,9 @@ export class Axios { requestOptions: opt } const { urlPrefix } = opt - // 拼接请求前缀如api - if (urlPrefix) { + // 绝对 URL(如图片地址)不拼接前缀,直接使用 + const isAbsoluteUrl = typeof config.url === 'string' && /^https?:\/\//i.test(config.url) + if (urlPrefix && !isAbsoluteUrl) { // 确保路径格式正确:/adminapi/xxx const url = config.url?.startsWith('/') ? config.url : `/${config.url}` axioxConfig.url = `/${urlPrefix}${url}` diff --git a/server/like-admin/src/main/java/com/mdd/admin/controller/TeacherController.java b/server/like-admin/src/main/java/com/mdd/admin/controller/TeacherController.java index c646f40a..bd163cf2 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/controller/TeacherController.java +++ b/server/like-admin/src/main/java/com/mdd/admin/controller/TeacherController.java @@ -15,6 +15,8 @@ import com.mdd.common.entity.system.SystemRole; import com.mdd.common.validator.annotation.IDMust; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -30,15 +32,15 @@ public class TeacherController { ITeacherService iTeacherService; @GetMapping("/list") - @ApiOperation(value="教师信息扩展列表") + @ApiOperation(value = "教师信息扩展列表") public AjaxResult> list(@Validated PageValidate pageValidate, - @Validated TeacherSearchValidate searchValidate) { + @Validated TeacherSearchValidate searchValidate) { PageResult list = iTeacherService.list(pageValidate, searchValidate); return AjaxResult.success(list); } @GetMapping("/detail") - @ApiOperation(value="教师信息扩展详情") + @ApiOperation(value = "教师信息扩展详情") public AjaxResult detail(@Validated @IDMust() @RequestParam("id") Integer id) { TeacherDetailVo detail = iTeacherService.detail(id); return AjaxResult.success(detail); @@ -46,14 +48,14 @@ public class TeacherController { @Log(title = "添加教师账号") @PostMapping("/add") - @ApiOperation(value="添加教师账号", notes = "根据提供的角色id列表,为添加的教师账号选择角色") + @ApiOperation(value = "添加教师账号", notes = "支持传入invitationCode(邀请码/二维码标识);根据提供的角色id列表,为添加的教师账号选择角色") public AjaxResult add(@Validated @RequestBody TeacherCreateValidate createValidate) { return iTeacherService.add(createValidate); } @Log(title = "教师信息扩展编辑") @PostMapping("/edit") - @ApiOperation(value="教师信息扩展编辑") + @ApiOperation(value = "教师信息扩展编辑", notes = "支持更新invitationCode(邀请码/二维码标识)") public AjaxResult edit(@Validated @RequestBody TeacherUpdateValidate updateValidate) { iTeacherService.edit(updateValidate); return AjaxResult.success(); @@ -61,7 +63,7 @@ public class TeacherController { @Log(title = "教师信息扩展删除") @PostMapping("/del") - @ApiOperation(value="教师信息扩展删除") + @ApiOperation(value = "教师信息扩展删除") public AjaxResult del(@Validated @RequestBody IdValidate idValidate) { iTeacherService.del(idValidate.getId()); return AjaxResult.success(); @@ -81,4 +83,29 @@ public class TeacherController { iTeacherService.roleConfig(idValidate.getId()); return AjaxResult.success(); } + + @Log(title = "生成邀请码") + @PostMapping("/generateInvitationCode") + @ApiOperation(value = "生成邀请码和二维码", notes = "为指定教师生成唯一的邀请码和二维码图片") + public AjaxResult generateInvitationCode(@Validated @RequestBody IdValidate idValidate) { + return iTeacherService.generateInvitationCode(idValidate.getId()); + } + + @GetMapping("/qrcode") + @ApiOperation(value = "获取二维码图片URL", notes = "获取指定教师的二维码图片访问地址") + public AjaxResult getQrCodeUrl(@Validated @IDMust() @RequestParam("id") Integer id) { + return iTeacherService.getQrCodeUrl(id); + } + + @GetMapping("/qrcode/image") + @ApiOperation(value = "获取二维码图片流", notes = "带鉴权返回教师二维码图片,用于前端展示与下载") + public ResponseEntity getQrCodeImage(@Validated @IDMust() @RequestParam("id") Integer id) { + byte[] bytes = iTeacherService.getQrCodeImageBytes(id); + if (bytes == null || bytes.length == 0) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok() + .contentType(MediaType.IMAGE_PNG) + .body(bytes); + } } diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/ITeacherService.java b/server/like-admin/src/main/java/com/mdd/admin/service/ITeacherService.java index 0cb6f322..de6148d1 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/ITeacherService.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/ITeacherService.java @@ -10,8 +10,6 @@ import com.mdd.common.core.AjaxResult; import com.mdd.common.core.PageResult; import com.mdd.common.entity.system.SystemRole; -import javax.management.relation.Role; - /** * 教师信息扩展服务接口类 * @author gyp @@ -64,4 +62,30 @@ public interface ITeacherService { void roleConfig(Integer id); AjaxResult getRoleConfig(); + + /** + * 生成邀请码和二维码 + * + * @param teacherId 教师ID + * @return AjaxResult 返回生成的邀请码 + * @author gyp + */ + AjaxResult generateInvitationCode(Integer teacherId); + + /** + * 获取二维码图片URL + * + * @author gyp + * @param teacherId 教师ID + * @return AjaxResult 返回二维码图片的绝对URL + */ + AjaxResult getQrCodeUrl(Integer teacherId); + + /** + * 获取二维码图片字节流(用于带鉴权的图片展示与下载) + * + * @param teacherId 教师ID + * @return 图片字节数组,不存在时返回 null + */ + byte[] getQrCodeImageBytes(Integer teacherId); } diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/impl/StudentInfoServiceImpl.java b/server/like-admin/src/main/java/com/mdd/admin/service/impl/StudentInfoServiceImpl.java index ac0e6207..9d878ab9 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/impl/StudentInfoServiceImpl.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/impl/StudentInfoServiceImpl.java @@ -29,6 +29,7 @@ import com.mdd.common.mapper.user.UserMapper; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.text.SimpleDateFormat; import com.mdd.common.util.*; import io.netty.util.internal.ThreadLocalRandom; @@ -92,6 +93,8 @@ public class StudentInfoServiceImpl implements IStudentInfoService { "=:academicWarnings@academic_warnings:int", "=:isVerified@is_verified:int", "=:verifiedBy@verified_by:int", + "=:recruitmentTeacherId@recruitment_teacher_id:int", + "=:receptionTeacherId@reception_teacher_id:int", }); IPage iPage = studentInfoMapper.selectPage(new Page<>(page, limit), queryWrapper); @@ -102,13 +105,27 @@ public class StudentInfoServiceImpl implements IStudentInfoService { BeanUtils.copyProperties(item, vo); vo.setVerifiedTime(TimeUtils.timestampToDate(item.getVerifiedTime())); - // 通过 student_id 关联查询基本信息获取 name + // 通过 student_id 关联查询基本信息获取姓名及基础信息 StudentBaseInfo baseInfo = studentBaseInfoMapper.selectOne( new QueryWrapper() .eq("student_id", item.getStudentId()) .last("limit 1")); if (baseInfo != null) { vo.setName(baseInfo.getName()); + vo.setGender(baseInfo.getGender()); + vo.setIdCard(baseInfo.getIdCard()); + vo.setPreviousSchool(baseInfo.getPreviousSchool()); + vo.setHeight(baseInfo.getHeight()); + vo.setWeight(baseInfo.getWeight()); + vo.setShoeSize(baseInfo.getShoeSize()); + } + + // 转换创建时间和更新时间为字符串格式 + if (item.getCreateTime() != null) { + vo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(item.getCreateTime())); + } + if (item.getUpdateTime() != null) { + vo.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(item.getUpdateTime())); } College college = collegeMapper.selectById(item.getCollegeId()); diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeacherServiceImpl.java b/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeacherServiceImpl.java index 02c93161..c4175a1e 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeacherServiceImpl.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeacherServiceImpl.java @@ -16,36 +16,43 @@ import com.mdd.admin.vo.teacher.TeacherDetailVo; import com.mdd.common.core.AjaxResult; import com.mdd.common.core.PageResult; import com.mdd.common.entity.College; -import com.mdd.common.entity.Config; import com.mdd.common.entity.Teacher; import com.mdd.common.entity.admin.Admin; import com.mdd.common.entity.admin.AdminRole; import com.mdd.common.entity.system.SystemRole; -import com.mdd.common.entity.user.User; import com.mdd.common.mapper.CollegeMapper; import com.mdd.common.mapper.TeacherMapper; import com.mdd.common.mapper.admin.AdminMapper; -import com.mdd.common.mapper.admin.AdminRoleMapper; import com.mdd.common.mapper.system.SystemRoleMapper; +import com.mdd.common.exception.OperateException; import com.mdd.common.util.ConfigUtils; +import com.mdd.common.util.QrCodeUtil; +import com.mdd.common.util.RandomUtil; import com.mdd.common.util.TimeUtils; +import com.mdd.common.util.ToolUtils; +import com.mdd.common.util.UrlUtils; +import com.mdd.common.util.YmlUtils; +import com.google.zxing.WriterException; + +import java.io.File; +import java.io.IOException; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.Resource; -import javax.management.relation.Role; import java.util.*; -import java.util.stream.Collectors; /** * 教师信息扩展实现类 + * * @author gyp */ @Service public class TeacherServiceImpl implements ITeacherService { - + @Resource TeacherMapper teacherMapper; @Autowired @@ -55,8 +62,6 @@ public class TeacherServiceImpl implements ITeacherService { @Autowired private AdminServiceImpl adminServiceImpl; @Autowired - private AdminRoleMapper adminRoleMapper; - @Autowired private AdminRoleServiceImpl adminRoleServiceImpl; @Autowired private SystemRoleMapper systemRoleMapper; @@ -64,42 +69,48 @@ public class TeacherServiceImpl implements ITeacherService { /** * 教师信息扩展列表 * - * @author gyp - * @param pageValidate 分页参数 + * @param pageValidate 分页参数 * @param searchValidate 搜索参数 * @return PageResult + * @author gyp */ @Override public PageResult list(PageValidate pageValidate, TeacherSearchValidate searchValidate) { - Integer page = pageValidate.getPage_no(); + Integer page = pageValidate.getPage_no(); Integer limit = pageValidate.getPage_size(); QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.orderByDesc("id"); + queryWrapper.orderByDesc("teacher_id"); teacherMapper.setSearch(queryWrapper, searchValidate, new String[]{ - "=:adminId@admin_id:int", - "like:name:str", + "like:name@teacher_name:str", "=:teacherCode@teacher_code:str", "=:collegeId@college_id:int", "=:teacherStatus@teacher_status:int", + "=:invitationCode@invitation_code:str", }); IPage iPage = teacherMapper.selectPage(new Page<>(page, limit), queryWrapper); List list = new LinkedList<>(); - for(Teacher item : iPage.getRecords()) { + for (Teacher item : iPage.getRecords()) { TeacherListedVo vo = new TeacherListedVo(); BeanUtils.copyProperties(item, vo); + // 映射主键:实体是teacherId,VO也是teacherId,BeanUtils会自动处理 + vo.setTeacherId(item.getTeacherId()); + // 显式设置教师工号,确保字段正确映射 + vo.setTeacherCode(item.getTeacherCode()); + // 兼容:前端列表使用name字段展示教师姓名,但教师表字段为teacher_name + vo.setName(item.getTeacherName()); + // 设置二维码URL(转换为绝对URL) + if (item.getQrcodeUrl() != null && !item.getQrcodeUrl().isEmpty()) { + // 后台端静态资源映射:/adminapi/uploads/**,因此这里需走 admin 端的绝对路径转换 + vo.setQrcodeUrl(UrlUtils.toAdminAbsoluteUrl(item.getQrcodeUrl())); + } vo.setCreateTime(TimeUtils.timestampToDate(item.getCreateTime())); vo.setUpdateTime(TimeUtils.timestampToDate(item.getUpdateTime())); College college = collegeMapper.selectById(vo.getCollegeId()); - if(college != null) vo.setCollegeName(college.getCollegeName()); - Admin admin = adminMapper.selectById(vo.getAdminId()); - if(admin != null) { - vo.setName(admin.getName()); - vo.setTeacherCode(admin.getAccount()); - } + if (college != null) vo.setCollegeName(college.getCollegeName()); list.add(vo); } @@ -110,53 +121,59 @@ public class TeacherServiceImpl implements ITeacherService { /** * 教师信息扩展详情 * - * @author gyp * @param id 主键参数 * @return Teacher + * @author gyp */ @Override public TeacherDetailVo detail(Integer id) { Teacher model = teacherMapper.selectOne( new QueryWrapper() - .eq("id", id) - .last("limit 1")); + .eq("teacher_id", id) + .last("limit 1")); Assert.notNull(model, "数据不存在"); TeacherDetailVo vo = new TeacherDetailVo(); BeanUtils.copyProperties(model, vo); - - - Admin admin = adminMapper.selectById(vo.getAdminId()); - if(admin != null) { - vo.setName(admin.getName()); - vo.setTeacherCode(admin.getAccount()); + // 映射主键:实体是teacherId,VO也是teacherId,BeanUtils会自动处理 + vo.setTeacherId(model.getTeacherId()); + // 显式设置教师工号,确保字段正确映射 + vo.setTeacherCode(model.getTeacherCode()); + // 兼容:前端详情使用name字段展示教师姓名,但教师表字段为teacher_name + vo.setName(model.getTeacherName()); + // 设置二维码URL(转换为绝对URL) + if (model.getQrcodeUrl() != null && !model.getQrcodeUrl().isEmpty()) { + // 后台端静态资源映射:/adminapi/uploads/**,因此这里需走 admin 端的绝对路径转换 + vo.setQrcodeUrl(UrlUtils.toAdminAbsoluteUrl(model.getQrcodeUrl())); } College college = collegeMapper.selectById(vo.getCollegeId()); - if(college != null) vo.setCollegeName(college.getCollegeName()); + if (college != null) vo.setCollegeName(college.getCollegeName()); return vo; } /** * 教师信息扩展新增 * - * @author gyp * @param createValidate 参数 + * @author gyp */ @Override public AjaxResult add(TeacherCreateValidate createValidate) { + // 自动生成唯一教师工号,作为管理员账号 & 教师工号 + String teacherCode = generateTeacherCode(); // 创建admin账号 SystemAdminCreateValidate admin = new SystemAdminCreateValidate(); - admin.setAccount(createValidate.getTeacherCode()); + admin.setAccount(teacherCode); admin.setName(createValidate.getName()); admin.setDisable(1); // 密码默认是电话号码后8位 admin.setPassword(createValidate.getContactPhone().substring(3)); int teacherRoleId; - try{ + try { teacherRoleId = Integer.parseInt(ConfigUtils.get("teacher", "teacher_role_id")); - }catch (NullPointerException e){ + } catch (NullPointerException e) { return AjaxResult.failed("未配置教师角色"); } admin.setRoleId(Collections.singletonList(teacherRoleId)); @@ -169,12 +186,19 @@ public class TeacherServiceImpl implements ITeacherService { queryWrapper.eq("account", admin.getAccount()); queryWrapper.isNull("delete_time"); Admin admin1 = adminMapper.selectOne(queryWrapper); - // 创建附属教师信息 + // 创建教师信息(注意:新表结构没有admin_id字段,所以不存储adminId) Teacher model = new Teacher(); - BeanUtils.copyProperties(createValidate, model); - model.setAdminId(admin1.getId()); - model.setCreateTime(System.currentTimeMillis()/1000); - model.setUpdateTime(System.currentTimeMillis()/1000); + model.setTeacherName(createValidate.getName()); + model.setTeacherCode(teacherCode); + model.setCollegeId(createValidate.getCollegeId()); + model.setContactPhone(createValidate.getContactPhone()); + model.setContactEmail(createValidate.getContactEmail()); + if (createValidate.getInvitationCode() != null && !createValidate.getInvitationCode().isEmpty()) { + model.setInvitationCode(createValidate.getInvitationCode()); + } + model.setTeacherStatus(1); // 默认在职 + model.setCreateTime(System.currentTimeMillis() / 1000); + model.setUpdateTime(System.currentTimeMillis() / 1000); teacherMapper.insert(model); return AjaxResult.success("添加信息成功"); @@ -183,24 +207,27 @@ public class TeacherServiceImpl implements ITeacherService { /** * 教师信息扩展编辑 * - * @author gyp * @param updateValidate 参数 + * @author gyp */ @Override public void edit(TeacherUpdateValidate updateValidate) { Teacher model = teacherMapper.selectOne( new QueryWrapper() - .eq("id", updateValidate.getId()) - .last("limit 1")); + .eq("teacher_id", updateValidate.getTeacherId()) + .last("limit 1")); Assert.notNull(model, "数据不存在!"); - model.setId(updateValidate.getId()); - model.setAdminId(updateValidate.getAdminId()); + model.setTeacherId(updateValidate.getTeacherId()); + model.setTeacherName(updateValidate.getName()); model.setCollegeId(updateValidate.getCollegeId()); model.setContactPhone(updateValidate.getContactPhone()); model.setContactEmail(updateValidate.getContactEmail()); model.setTeacherStatus(updateValidate.getTeacherStatus()); + if (updateValidate.getInvitationCode() != null) { + model.setInvitationCode(updateValidate.getInvitationCode()); + } model.setUpdateTime(System.currentTimeMillis() / 1000); teacherMapper.updateById(model); } @@ -208,52 +235,53 @@ public class TeacherServiceImpl implements ITeacherService { /** * 教师信息扩展删除 * - * @author gyp * @param id 主键ID + * @author gyp */ @Override public void del(Integer id) { Teacher model = teacherMapper.selectOne( new QueryWrapper() - .eq("id", id) - .last("limit 1")); + .eq("teacher_id", id) + .last("limit 1")); Assert.notNull(model, "数据不存在!"); - teacherMapper.delete(new QueryWrapper().eq("id", id)); + teacherMapper.delete(new QueryWrapper().eq("teacher_id", id)); } /** * 配置教师的角色的ID - * */ + */ @Override public void roleConfig(Integer id) { QueryWrapper queryWrapper = null; // 存放教师列表 List isTeacher = new ArrayList<>(); int originalRoleId = -1; // 初始ID为-1,应该不会出现-1的ID - try{ + try { // 查找原教师配置的所有教师 originalRoleId = Integer.parseInt(ConfigUtils.get("teacher", "teacher_role_id")); List adminRoleList = adminRoleServiceImpl.getAdminIdByRoleId(originalRoleId); isTeacher.addAll(adminRoleList); - }catch (NullPointerException ignored){} // 忽视此处因为查找不到的报错 + } catch (NullPointerException ignored) { + } // 忽视此处因为查找不到的报错 // 若配置不存在,会新建配置 - ConfigUtils.set("teacher","teacher_role_id",id.toString()); + ConfigUtils.set("teacher", "teacher_role_id", id.toString()); // 将原本的所有教师的角色ID更新 - if(!isTeacher.isEmpty()) { + if (!isTeacher.isEmpty()) { // 对每个教师的角色重新分配 for (AdminRole adminRole : isTeacher) { List roleIds = adminRoleServiceImpl.getRoleIdAttr(adminRole.getAdminId()); - for(int i = 0; i < roleIds.size(); i++){ + for (int i = 0; i < roleIds.size(); i++) { // 替换原教师角色 - if(roleIds.get(i) == originalRoleId){ + if (roleIds.get(i) == originalRoleId) { roleIds.set(i, id); } // 删除重复分配 - else if(roleIds.get(i).equals(id)){ + else if (roleIds.get(i).equals(id)) { roleIds.remove(i); i--; } @@ -275,15 +303,269 @@ public class TeacherServiceImpl implements ITeacherService { return AjaxResult.success(role); } + /** + * 生成唯一教师工号:T + 时间戳秒 + 3位随机数 + */ + private String generateTeacherCode() { + String code; + do { + code = "T" + (System.currentTimeMillis() / 1000) + RandomUtil.randomNumber(3); + } while (teacherMapper.selectCount(new QueryWrapper().eq("teacher_code", code)) > 0); + return code; + } + public String getNameById(Integer teacherId) { Teacher teacher = teacherMapper.selectById(teacherId); - if(teacher == null){ + if (teacher == null) { return null; } - Admin admin = adminMapper.selectById(teacher.getAdminId()); - if(admin == null){ + return teacher.getTeacherName(); + } + + /** + * 生成邀请码和二维码 + * + * @param teacherId 教师ID + * @return AjaxResult 返回生成的邀请码 + */ + @Override + public AjaxResult generateInvitationCode(Integer teacherId) { + Teacher teacher = teacherMapper.selectOne( + new QueryWrapper() + .eq("teacher_id", teacherId) + .last("limit 1")); + + Assert.notNull(teacher, "教师不存在!"); + + // 生成唯一邀请码:INV + 时间戳(秒) + 6位随机字符串 + String invitationCode; + do { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String randomStr = ToolUtils.randomString(6).toUpperCase(); + invitationCode = "INV" + timestamp + randomStr; + } while (teacherMapper.selectCount( + new QueryWrapper() + .eq("invitation_code", invitationCode) + .ne("teacher_id", teacherId)) > 0); + + // 生成二维码内容URL(预报名页面地址) + String qrCodeContent = buildQrCodeUrl(invitationCode); + + // 生成二维码图片并保存 + String qrcodeUrl = generateAndSaveQrCode(invitationCode, qrCodeContent, teacherId); + + // 更新教师表的邀请码和二维码地址 + teacher.setInvitationCode(invitationCode); + teacher.setQrcodeUrl(qrcodeUrl); + teacher.setUpdateTime(System.currentTimeMillis() / 1000); + teacherMapper.updateById(teacher); + + return AjaxResult.success(invitationCode); + } + + /** + * 构建二维码内容URL(预报名页面地址) + * + * @param invitationCode 邀请码 + * @return 完整的预报名页面URL + */ + private String buildQrCodeUrl(String invitationCode) { + // 优先从配置中读取预报名H5地址(建议配置为 uniapp H5 根,如:https://xx.com/h5) + String h5BaseUrl = ConfigUtils.get("pre_registration", "front_url", ""); + + if (h5BaseUrl == null || h5BaseUrl.isEmpty()) { + // 如果没有单独配置,尝试从 yml 中读取 like.front-url + String frontUrl = YmlUtils.get("like.front-url"); + if (frontUrl != null && !frontUrl.isEmpty()) { + h5BaseUrl = frontUrl; + } else { + // 再退一步,使用当前请求域名 + h5BaseUrl = UrlUtils.getRequestUrl(); + } + } + + if (h5BaseUrl == null) { + h5BaseUrl = ""; + } + + // 移除末尾的斜杠,方便统一拼接 + while (h5BaseUrl.endsWith("/")) { + h5BaseUrl = h5BaseUrl.substring(0, h5BaseUrl.length() - 1); + } + + String fullUrl; + if (h5BaseUrl.contains("#/")) { + // 如果已经配置了完整的 hash 路径(例如:https://xx.com/h5/#/pages/pre_registration/pre_registration) + // 这里只负责追加或合并 invitationCode 参数 + if (h5BaseUrl.contains("?")) { + fullUrl = h5BaseUrl + "&invitationCode=" + invitationCode; + } else { + fullUrl = h5BaseUrl + "?invitationCode=" + invitationCode; + } + } else { + // 默认拼接为小程序路径(去除H5的hash模式,以便微信扫码直接进入小程序): + // {h5BaseUrl}/pages/pre_registration/pre_registration?invitationCode=xxx + fullUrl = h5BaseUrl + /*+ "/pages/pre_registration/pre_registration.html" + + "?invitationCode=" + invitationCode*/; + } + + return fullUrl; + } + + /** + * 生成二维码图片并保存(方案B:本地存储,预留方案A:OSS上传) + * + * @param invitationCode 邀请码 + * @param qrCodeContent 二维码内容 + * @param teacherId 教师ID + * @return 二维码图片的相对路径URL + */ + private String generateAndSaveQrCode(String invitationCode, String qrCodeContent, Integer teacherId) { + try { + // 二维码图片尺寸 + int qrCodeWidth = 300; + int qrCodeHeight = 300; + + // 获取存储引擎配置 + String engine = ConfigUtils.get("storage", "default", "local"); + engine = engine == null || engine.isEmpty() ? "local" : engine; + + String qrcodeUrl; + String date = TimeUtils.timestampToDate(TimeUtils.timestamp(), "yyyyMMdd"); + String fileName = "teacher_" + teacherId + "_" + invitationCode + ".png"; + String fileKey = date + "/" + fileName; + + if ("local".equals(engine)) { + // ========== 方案B:本地存储 ========== + String directory = YmlUtils.get("like.upload-directory"); + if (directory == null || directory.isEmpty()) { + throw new OperateException("请配置上传目录like.upload-directory"); + } + + String folder = "qrcode/teacher"; + String savePath = (directory + folder + "/" + date).replace("\\", "/"); + File saveDir = new File(savePath); + if (!saveDir.exists()) { + if (!saveDir.mkdirs()) { + throw new OperateException("创建二维码保存目录失败"); + } + } + + File qrCodeFile = new File(savePath, fileName); + QrCodeUtil.generateQrCodeToFile(qrCodeContent, qrCodeWidth, qrCodeHeight, qrCodeFile.getAbsolutePath()); + + // 返回相对路径 + qrcodeUrl = folder + "/" + fileKey; + + } else { + // ========== 方案A:OSS上传(预留代码) ========== + // 注意:OSS上传需要MultipartFile,这里需要将byte[]转换为临时文件再上传 + // 或者直接使用OSS的putObject方法上传字节流 + + // 方案A-1:使用临时文件上传(适用于所有OSS) + File tempFile = File.createTempFile("qrcode_", ".png"); + try { + QrCodeUtil.generateQrCodeToFile(qrCodeContent, qrCodeWidth, qrCodeHeight, tempFile.getAbsolutePath()); + + String folder = "qrcode/teacher"; + String ossKey = folder + "/" + fileKey; + + if ("aliyun".equals(engine)) { + // 阿里云OSS上传 + /* + Map config = ConfigUtils.getMap("storage", "aliyun"); + AliyunStorage aliyunStorage = new AliyunStorage(config); + // 需要将File转换为MultipartFile或使用OSS的putObject方法 + // 这里使用OSS直接上传字节流的方式 + com.aliyun.oss.OSS ossClient = aliyunStorage.ossClient(); + try { + ossClient.putObject(config.get("bucket"), ossKey, new FileInputStream(tempFile)); + qrcodeUrl = ossKey; + } finally { + ossClient.shutdown(); + } + */ + // TODO: 实现阿里云OSS上传逻辑 + qrcodeUrl = ossKey; + } else if ("qiniu".equals(engine)) { + // 七牛云上传 + // TODO: 实现七牛云上传逻辑 + qrcodeUrl = ossKey; + } else if ("qcloud".equals(engine)) { + // 腾讯云COS上传 + // TODO: 实现腾讯云COS上传逻辑 + qrcodeUrl = ossKey; + } else { + throw new OperateException("不支持的存储引擎: " + engine); + } + } finally { + // 删除临时文件 + if (tempFile.exists()) { + tempFile.delete(); + } + } + } + + return qrcodeUrl; + + } catch (WriterException | IOException e) { + throw new OperateException("生成二维码失败: " + e.getMessage()); + } + } + + /** + * 获取二维码图片URL + * + * @param teacherId 教师ID + * @return AjaxResult 返回二维码图片的绝对URL + */ + @Override + public AjaxResult getQrCodeUrl(Integer teacherId) { + Teacher teacher = teacherMapper.selectOne( + new QueryWrapper() + .eq("teacher_id", teacherId) + .last("limit 1")); + + Assert.notNull(teacher, "教师不存在!"); + + if (teacher.getQrcodeUrl() == null || teacher.getQrcodeUrl().isEmpty()) { + return AjaxResult.failed("该教师尚未生成二维码,请先生成邀请码"); + } + + // 转换为后台端可访问的绝对URL(/adminapi/uploads/**) + String absoluteUrl = UrlUtils.toAdminAbsoluteUrl(teacher.getQrcodeUrl()); + return AjaxResult.success(absoluteUrl); + } + + @Override + public byte[] getQrCodeImageBytes(Integer teacherId) { + Teacher teacher = teacherMapper.selectOne( + new QueryWrapper() + .eq("teacher_id", teacherId) + .last("limit 1")); + if (teacher == null || teacher.getQrcodeUrl() == null || teacher.getQrcodeUrl().isEmpty()) { + return null; + } + String engine = ConfigUtils.get("storage", "default", "local"); + engine = engine == null || engine.isEmpty() ? "local" : engine; + if (!"local".equals(engine)) { + return null; + } + String directory = YmlUtils.get("like.upload-directory"); + if (directory == null || directory.isEmpty()) { + return null; + } + String path = teacher.getQrcodeUrl().startsWith("/") ? teacher.getQrcodeUrl() : "/" + teacher.getQrcodeUrl(); + String fullPath = (directory + path).replace("\\", "/"); + java.io.File file = new java.io.File(fullPath); + if (!file.exists() || !file.isFile()) { + return null; + } + try { + return java.nio.file.Files.readAllBytes(file.toPath()); + } catch (java.io.IOException e) { return null; } - return admin.getName(); } } diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeachingTaskServiceImpl.java b/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeachingTaskServiceImpl.java index 2d16d781..110ffeaa 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeachingTaskServiceImpl.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/impl/TeachingTaskServiceImpl.java @@ -90,7 +90,9 @@ public class TeachingTaskServiceImpl implements ITeachingTaskService { Course course = courseMapper.selectById(courseId); Teacher teacher = teacherMapper.selectById(teacherId); Class clazz = classMapper.selectById(classId); - Admin adminTeacher = adminMapper.selectById(teacher.getAdminId()); + Admin adminTeacher = adminMapper.selectOne( + new QueryWrapper() + .eq("account", teacher.getTeacherCode())); Admin adminCreator = adminMapper.selectById(createdBy); Admin adminUpdater = adminMapper.selectById(updatedBy); vo.setSemesterName(semester.getSemesterName()); @@ -131,7 +133,9 @@ public class TeachingTaskServiceImpl implements ITeachingTaskService { Course course = courseMapper.selectById(courseId); Teacher teacher = teacherMapper.selectById(teacherId); Class clazz = classMapper.selectById(classId); - Admin adminTeacher = adminMapper.selectById(teacher.getAdminId()); + Admin adminTeacher = adminMapper.selectOne( + new QueryWrapper() + .eq("account", teacher.getTeacherCode())); vo.setSemesterName(semester.getSemesterName()); vo.setCourseName(course.getCourseName()); vo.setClassName(clazz.getClassName()); @@ -248,7 +252,7 @@ public class TeachingTaskServiceImpl implements ITeachingTaskService { for(Teacher teacher : teachers){ // 将在名单的教师记录 for(TeacherCourse teacherCourse : teacherCourses){ - if(teacher.getId().equals(teacherCourse.getTeacherId())){ + if(teacher.getTeacherId().equals(teacherCourse.getTeacherId())){ teacherIds.add(teacherCourse.getTeacherId()); } } @@ -257,7 +261,7 @@ public class TeachingTaskServiceImpl implements ITeachingTaskService { } List teacherIds = new ArrayList<>(); for (Teacher teacher : teachers) { - teacherIds.add(teacher.getId()); + teacherIds.add(teacher.getTeacherId()); } return AjaxResult.success(teacherIds); } diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/StudentInfoSearchValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/StudentInfoSearchValidate.java index c9c9bfa7..829c212a 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/validate/StudentInfoSearchValidate.java +++ b/server/like-admin/src/main/java/com/mdd/admin/validate/StudentInfoSearchValidate.java @@ -50,4 +50,10 @@ public class StudentInfoSearchValidate implements Serializable { @ApiModelProperty(value = "认证人ID") private Integer verifiedBy; + @ApiModelProperty(value = "招生老师ID") + private Integer recruitmentTeacherId; + + @ApiModelProperty(value = "接待老师ID") + private Integer receptionTeacherId; + } diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherCreateValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherCreateValidate.java index 824716b7..b654dfd8 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherCreateValidate.java +++ b/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherCreateValidate.java @@ -15,8 +15,7 @@ public class TeacherCreateValidate implements Serializable { private static final long serialVersionUID = 1L; - @NotEmpty(message = "账号不能为空") - @ApiModelProperty(value = "教师工号", required = true) + @ApiModelProperty(value = "教师工号(系统自动生成)") private String teacherCode; @NotEmpty(message = "姓名不能为空") @@ -31,4 +30,7 @@ public class TeacherCreateValidate implements Serializable { @ApiModelProperty(value = "联系邮箱") private String contactEmail; + + @ApiModelProperty(value = "邀请码(二维码地址标识)") + private String invitationCode; } diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherSearchValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherSearchValidate.java index ffbc6309..e494c3e0 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherSearchValidate.java +++ b/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherSearchValidate.java @@ -14,9 +14,6 @@ public class TeacherSearchValidate implements Serializable { @ApiModelProperty(value = "姓名") private String name; - @ApiModelProperty(value = "关联管理员ID") - private Integer adminId; - @ApiModelProperty(value = "教师工号") private String teacherCode; @@ -26,4 +23,7 @@ public class TeacherSearchValidate implements Serializable { @ApiModelProperty(value = "教师状态:1-在职,2-休假,3-离职") private Integer teacherStatus; + @ApiModelProperty(value = "邀请码(二维码地址标识)") + private String invitationCode; + } diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherUpdateValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherUpdateValidate.java index 63965d33..5f892477 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherUpdateValidate.java +++ b/server/like-admin/src/main/java/com/mdd/admin/validate/teacher/TeacherUpdateValidate.java @@ -17,12 +17,12 @@ public class TeacherUpdateValidate implements Serializable { private static final long serialVersionUID = 1L; - @IDMust(message = "id参数必传且需大于0") - @ApiModelProperty(value = "") - private Integer id; + @IDMust(message = "teacherId参数必传且需大于0") + @ApiModelProperty(value = "教师ID") + private Integer teacherId; - @ApiModelProperty(value = "关联管理员ID") - private Integer adminId; + @ApiModelProperty(value = "姓名") + private String name; @ApiModelProperty(value = "教师工号") private String teacherCode; @@ -42,4 +42,7 @@ public class TeacherUpdateValidate implements Serializable { @ApiModelProperty(value = "教师状态:1-在职,2-休假,3-离职") private Integer teacherStatus; + @ApiModelProperty(value = "邀请码(二维码地址标识)") + private String invitationCode; + } diff --git a/server/like-admin/src/main/java/com/mdd/admin/vo/StudentInfoListedVo.java b/server/like-admin/src/main/java/com/mdd/admin/vo/StudentInfoListedVo.java index dc94ee0a..6de6486f 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/vo/StudentInfoListedVo.java +++ b/server/like-admin/src/main/java/com/mdd/admin/vo/StudentInfoListedVo.java @@ -7,6 +7,7 @@ import lombok.Data; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigDecimal; +import java.util.Date; @Data @ApiModel("学生信息列表Vo") @@ -71,6 +72,18 @@ public class StudentInfoListedVo implements Serializable { @ApiModelProperty(value = "学业预警: [0=无, 1=一级预警, 2=二级预警, 3=三级预警]") private Integer academicWarnings; + @ApiModelProperty(value = "中考成绩") + private BigDecimal highSchoolScore; + + @ApiModelProperty(value = "预报名金额") + private BigDecimal preRegistrationAmount; + + @ApiModelProperty(value = "招生老师ID") + private Integer recruitmentTeacherId; + + @ApiModelProperty(value = "接待老师ID") + private Integer receptionTeacherId; + @ApiModelProperty(value = "是否认证: [0=未认证, 1=已认证]") private Integer isVerified; diff --git a/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherDetailVo.java b/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherDetailVo.java index 6c5bea39..bc9327e7 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherDetailVo.java +++ b/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherDetailVo.java @@ -12,15 +12,12 @@ public class TeacherDetailVo implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "") - private Integer id; + @ApiModelProperty(value = "教师ID") + private Integer teacherId; @ApiModelProperty(value = "姓名") private String name; - @ApiModelProperty(value = "关联管理员ID") - private Integer adminId; - @ApiModelProperty(value = "教师工号") private String teacherCode; @@ -42,5 +39,10 @@ public class TeacherDetailVo implements Serializable { @ApiModelProperty(value = "教师状态:1-在职,2-休假,3-离职") private Integer teacherStatus; + @ApiModelProperty(value = "邀请码(二维码地址标识)") + private String invitationCode; + + @ApiModelProperty(value = "二维码图片地址") + private String qrcodeUrl; } diff --git a/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherListedVo.java b/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherListedVo.java index 694d1dd5..e88ca11c 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherListedVo.java +++ b/server/like-admin/src/main/java/com/mdd/admin/vo/teacher/TeacherListedVo.java @@ -12,15 +12,12 @@ public class TeacherListedVo implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "") - private Integer id; + @ApiModelProperty(value = "教师ID") + private Integer teacherId; @ApiModelProperty(value = "姓名") private String name; - @ApiModelProperty(value = "关联管理员ID") - private Integer adminId; - @ApiModelProperty(value = "学院名") private String collegeName; @@ -42,6 +39,12 @@ public class TeacherListedVo implements Serializable { @ApiModelProperty(value = "教师状态:1-在职,2-休假,3-离职") private Integer teacherStatus; + @ApiModelProperty(value = "邀请码(二维码地址标识)") + private String invitationCode; + + @ApiModelProperty(value = "二维码图片地址") + private String qrcodeUrl; + @ApiModelProperty(value = "创建时间") private String createTime; diff --git a/server/like-common/src/main/java/com/mdd/common/entity/Teacher.java b/server/like-common/src/main/java/com/mdd/common/entity/Teacher.java index ddbf4403..a1ed942d 100644 --- a/server/like-common/src/main/java/com/mdd/common/entity/Teacher.java +++ b/server/like-common/src/main/java/com/mdd/common/entity/Teacher.java @@ -15,13 +15,17 @@ public class Teacher implements Serializable { private static final long serialVersionUID = 1L; - @TableId(value="id", type= IdType.AUTO) - @ApiModelProperty(value = "") - private Integer id; + @TableId(value="teacher_id", type= IdType.AUTO) + @ApiModelProperty(value = "教师ID") + private Integer teacherId; - @TableField("admin_id") - @ApiModelProperty(value = "关联管理员ID") - private Integer adminId; + @TableField("teacher_name") + @ApiModelProperty(value = "教师姓名") + private String teacherName; + + @TableField("teacher_code") + @ApiModelProperty(value = "教师工号") + private String teacherCode; @ApiModelProperty(value = "所属院系ID") private Integer collegeId; @@ -35,6 +39,14 @@ public class Teacher implements Serializable { @ApiModelProperty(value = "教师状态:1-在职,2-休假,3-离职") private Integer teacherStatus; + @TableField("invitation_code") + @ApiModelProperty(value = "邀请码(二维码地址标识)") + private String invitationCode; + + @TableField("qrcode_url") + @ApiModelProperty(value = "二维码图片地址") + private String qrcodeUrl; + @ApiModelProperty(value = "创建时间") private Long createTime; diff --git a/server/like-common/src/main/java/com/mdd/common/util/QrCodeUtil.java b/server/like-common/src/main/java/com/mdd/common/util/QrCodeUtil.java new file mode 100644 index 00000000..07957f68 --- /dev/null +++ b/server/like-common/src/main/java/com/mdd/common/util/QrCodeUtil.java @@ -0,0 +1,96 @@ +package com.mdd.common.util; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * 二维码生成工具类 + */ +public class QrCodeUtil { + + /** + * 生成二维码图片并保存到文件 + * + * @param content 二维码内容 + * @param width 图片宽度 + * @param height 图片高度 + * @param filePath 保存文件路径 + * @throws WriterException 写入异常 + * @throws IOException IO异常 + */ + public static void generateQrCodeToFile(String content, int width, int height, String filePath) throws WriterException, IOException { + BufferedImage image = generateQrCodeImage(content, width, height); + File file = new File(filePath); + // 确保父目录存在 + File parentDir = file.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); + } + ImageIO.write(image, "png", file); + } + + /** + * 生成二维码图片(BufferedImage) + * + * @param content 二维码内容 + * @param width 图片宽度 + * @param height 图片高度 + * @return BufferedImage + * @throws WriterException 写入异常 + */ + public static BufferedImage generateQrCodeImage(String content, int width, int height) throws WriterException { + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + hints.put(EncodeHintType.MARGIN, 1); + + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints); + + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D graphics = image.createGraphics(); + graphics.setColor(Color.WHITE); + graphics.fillRect(0, 0, width, height); + graphics.setColor(Color.BLACK); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (bitMatrix.get(x, y)) { + graphics.fillRect(x, y, 1, 1); + } + } + } + graphics.dispose(); + return image; + } + + /** + * 生成二维码图片字节数组 + * + * @param content 二维码内容 + * @param width 图片宽度 + * @param height 图片高度 + * @return 图片字节数组 + * @throws WriterException 写入异常 + * @throws IOException IO异常 + */ + public static byte[] generateQrCodeBytes(String content, int width, int height) throws WriterException, IOException { + BufferedImage image = generateQrCodeImage(content, width, height); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ImageIO.write(image, "png", outputStream); + return outputStream.toByteArray(); + } +}