From da8010bf69541b5aa0efe81c75105d496a28bb0a Mon Sep 17 00:00:00 2001 From: Dcx12138 <2320898596@qq.com> Date: Sun, 15 Dec 2024 17:19:01 +0800 Subject: [PATCH] =?UTF-8?q?readme=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: SmileToCandy --- .../java/com/tamguo/web/BookController.java | 56 +++++- .../java/com/tamguo/web/CourseController.java | 84 ++++++-- .../com/tamguo/web/FileUploadController.java | 83 ++++++-- .../java/com/tamguo/web/IndexController.java | 59 ++++-- .../java/com/tamguo/web/LoginController.java | 130 +++++++++--- .../java/com/tamguo/web/PaperController.java | 189 ++++++++++++++---- .../com/tamguo/web/PasswordController.java | 129 +++++++++--- .../com/tamguo/web/QuestionContrller.java | 125 +++++++++--- .../com/tamguo/web/RegisterController.java | 74 +++++-- .../com/tamguo/web/SubjectController.java | 104 +++++++--- .../com/tamguo/web/UEditorController.java | 139 ++++++++++--- .../tamguo/web/teacher/JoinusController.java | 35 +++- 12 files changed, 972 insertions(+), 235 deletions(-) diff --git a/tamguo/src/main/java/com/tamguo/web/BookController.java b/tamguo/src/main/java/com/tamguo/web/BookController.java index 45911a2..015c3bb 100644 --- a/tamguo/src/main/java/com/tamguo/web/BookController.java +++ b/tamguo/src/main/java/com/tamguo/web/BookController.java @@ -19,40 +19,86 @@ import com.tamguo.service.IChapterService; import com.tamguo.service.ICourseService; import com.tamguo.service.ISubjectService; +// 标识这是一个Spring的控制器类,用于处理与书籍相关的Web请求,并返回相应的视图或数据 @Controller public class BookController { + // 自动注入IBookService,用于处理书籍相关的业务逻辑,比如根据ID查询书籍等操作 @Autowired IBookService iBookService; + + // 自动注入IChapterService,用于处理章节相关的业务逻辑,例如查询某书籍下的章节列表等操作 @Autowired IChapterService iChapterService; + + // 自动注入ISubjectService,用于处理学科相关的业务逻辑,像根据学科ID查询学科信息等操作 @Autowired ISubjectService iSubjectService; + + // 自动注入ICourseService,用于处理课程相关的业务逻辑,例如查询课程信息等操作 @Autowired ICourseService iCourseService; - + + /** + * 处理书籍详情页面的GET请求,根据传入的书籍唯一标识符(uid),查询并获取与该书籍相关的各种信息(如所属学科、课程、同课程下的其他书籍、自身的章节列表等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"book",最后返回该ModelAndView对象用于渲染相应的书籍详情页面视图给用户。 + * 如果在查询过程中出现异常,则将视图名称设置为"404",返回相应的ModelAndView对象,表示出现错误情况(可能展示404页面给用户)。 + * + * @param uid 书籍的唯一标识符,用于定位要展示详情的具体书籍 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中 + * @return 返回包含视图名称和相关书籍及关联数据的ModelAndView对象,用于渲染相应的页面视图 + */ @SuppressWarnings("unchecked") @RequestMapping(value = {"book/{uid}"}, method = RequestMethod.GET) - public ModelAndView index(@PathVariable String uid , ModelAndView model) { + public ModelAndView index(@PathVariable String uid, ModelAndView model) { try { + // 根据传入的书籍ID,通过书籍服务查询并获取对应的书籍实体信息 BookEntity book = iBookService.selectById(uid); + + // 根据书籍所属的学科ID,通过学科服务查询并获取对应的学科实体信息 SubjectEntity subject = iSubjectService.find(book.getSubjectId()); + + // 获取该学科下包含的课程列表信息(假设SubjectEntity类中有相应的字段存储课程列表,这里获取该列表) List courseList = subject.getCourseList(); + + // 通过条件查询,查找与当前书籍属于同一课程的其他书籍列表,用于可能在页面展示相关推荐书籍等场景 List bookList = iBookService.selectList(Condition.create().eq("course_id", book.getCourseId())); + + // 根据书籍所属的课程ID,通过课程服务查询并获取对应的课程实体信息 CourseEntity course = iCourseService.selectById(book.getCourseId()); + + // 通过条件查询,获取当前书籍下的所有章节列表信息,用于在书籍详情页面展示书籍的章节结构等内容 List chapterList = iChapterService.selectList(Condition.create().eq("book_id", uid)); + + // 将查询到的书籍实体信息添加到ModelAndView对象中,以便在视图中可以获取并展示书籍的详细内容 model.addObject("book", book); + + // 将查询到的学科实体信息添加到ModelAndView对象中,以便在视图中展示书籍所属学科等相关信息 model.addObject("subject", subject); + + // 将查询到的课程实体信息添加到ModelAndView对象中,以便在视图中展示书籍所属课程等相关信息 model.addObject("course", course); - model.addObject("chapterList" , chapterList); + + // 将查询到的书籍章节列表信息添加到ModelAndView对象中,以便在视图中展示书籍的章节情况 + model.addObject("chapterList", chapterList); + + // 将查询到的同课程下的其他书籍列表信息添加到ModelAndView对象中,以便在视图中展示相关推荐书籍等内容 model.addObject("courseList", courseList); + + // 将查询到的本课程下的所有书籍列表信息添加到ModelAndView对象中,以便在视图中展示相关推荐书籍等内容 model.addObject("bookList", bookList); + + // 设置视图名称为"book",对应相应的书籍详情页面模板,后续会根据这个名称去查找并渲染对应的视图 model.setViewName("book"); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户 return model; } catch (Exception e) { + // 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况 model.setViewName("404"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出404页面展示给用户 return model; } } - -} + +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/CourseController.java b/tamguo/src/main/java/com/tamguo/web/CourseController.java index 6b1e23f..b15682e 100644 --- a/tamguo/src/main/java/com/tamguo/web/CourseController.java +++ b/tamguo/src/main/java/com/tamguo/web/CourseController.java @@ -10,9 +10,9 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; /** * Controller - 科目 - * - * @author tamguo + * 该类主要作为Spring的控制器,用于处理与课程(Course)相关的Web请求,比如获取课程详情、课程下的章节信息等,并返回相应的视图或数据。 * + * @author tamguo */ import org.springframework.web.servlet.ModelAndView; @@ -27,54 +27,112 @@ import com.tamguo.service.ICourseService; import com.tamguo.service.ISubjectService; import com.tamguo.util.Result; +// 标识这是一个Spring的控制器类,用于处理课程相关的Web请求,并返回相应的视图或数据 @Controller public class CourseController { - + + // 自动注入IChapterService,用于处理章节相关的业务逻辑,例如查询课程对应的章节信息、获取章节树结构等操作 @Autowired IChapterService iChapterService; + + // 自动注入ICourseService,用于处理课程相关的业务逻辑,像根据课程ID查找课程、按学科ID查找课程列表等操作 @Autowired ICourseService iCourseService; + + // 自动注入ISubjectService,用于处理学科相关的业务逻辑,例如根据学科ID查找学科信息等操作 @Autowired ISubjectService iSubjectService; + + // 自动注入IBookService,用于处理书籍相关的业务逻辑,比如根据课程ID查询相关书籍列表等操作 @Autowired IBookService iBookService; + /** + * 处理课程详情页面的GET请求,根据传入的课程唯一标识符(uid),查询并获取与该课程相关的各种信息(如所属学科、包含的书籍列表、首本书籍、课程下的章节列表、同学科下的其他课程列表等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"chapter",最后返回该ModelAndView对象用于渲染相应的课程详情页面视图给用户。 + * 如果在查询过程中出现异常,则将视图名称设置为"404",返回相应的ModelAndView对象,表示出现错误情况(可能展示404页面给用户)。 + * + * @param uid 课程的唯一标识符,用于定位要展示详情的具体课程 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中 + * @return 返回包含视图名称和相关课程及关联数据的ModelAndView对象,用于渲染相应的页面视图 + */ @SuppressWarnings("unchecked") @RequestMapping(value = {"course/{uid}"}, method = RequestMethod.GET) - public ModelAndView index(@PathVariable String uid , ModelAndView model) { + public ModelAndView index(@PathVariable String uid, ModelAndView model) { try { + // 根据传入的课程ID,通过课程服务查询并获取对应的课程实体信息 CourseEntity course = iCourseService.find(uid); + + // 通过条件查询,查找与当前课程相关的所有书籍列表,可能用于展示该课程下有哪些相关书籍等场景 List bookList = iBookService.selectList(Condition.create().eq("course_id", uid)); + + // 获取书籍列表中的第一本图书实体信息(这里假设取第一本作为某种默认展示或后续处理的依据,具体业务逻辑可能需根据实际情况调整) BookEntity book = bookList.get(0); + + // 根据课程所属的学科ID,通过学科服务查询并获取对应的学科实体信息 SubjectEntity subject = iSubjectService.find(course.getSubjectId()); + + // 通过章节服务,查询并获取当前课程对应的章节列表信息,用于在课程详情页面展示课程包含的章节内容等 List chapterList = iChapterService.findCourseChapter(book.getUid()); + + // 通过课程服务,查找与当前课程属于同一学科的其他课程列表,可能用于相关课程推荐等场景 List courseList = iCourseService.findBySubjectId(course.getSubjectId()); - + + // 将查询到的课程章节列表信息添加到ModelAndView对象中,以便在视图中展示课程的章节情况 model.addObject("chapterList", chapterList); + + // 将查询到的同学科下的其他课程列表信息添加到ModelAndView对象中,以便在视图中展示相关课程推荐等内容 model.addObject("courseList", courseList); + + // 将查询到的课程实体信息添加到ModelAndView对象中,以便在视图中展示课程的详细信息 model.addObject("course", course); + + // 将查询到的学科实体信息添加到ModelAndView对象中,以便在视图中展示课程所属学科等相关信息 model.addObject("subject", subject); + + // 将查询到的课程相关的书籍列表信息添加到ModelAndView对象中,以便在视图中展示课程包含的书籍等内容 model.addObject("bookList", bookList); - model.addObject("book" , book); - + + // 将获取到的首本图书实体信息添加到ModelAndView对象中(具体用途根据业务而定) + model.addObject("book", book); + + // 设置视图名称为"chapter",对应相应的课程详情页面模板,后续会根据这个名称去查找并渲染对应的视图 model.setViewName("chapter"); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户 return model; } catch (Exception e) { + // 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况 model.setViewName("404"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出404页面展示给用户 return model; } } - + + /** + * 处理根据课程ID查找课程章节的GET请求,直接调用章节服务的相应方法,根据传入的课程ID查找对应的章节列表信息,并将查找结果(章节列表)返回给前端。 + * 该方法返回的是具体的章节实体列表,方便前端直接使用这些数据进行展示或其他相关操作。 + * + * @param courseId 课程的唯一标识符,用于定位要查找章节的具体课程 + * @return 返回包含指定课程下所有章节实体信息的List列表,若未找到则返回空列表 + */ @RequestMapping(value = {"course/findChapter"}, method = RequestMethod.GET) @ResponseBody - public List findChapterByCourseId(String courseId){ + public List findChapterByCourseId(String courseId) { return iChapterService.findCourseChapter(courseId); } - + + /** + * 处理根据课程ID查找课程章节树的GET请求,调用章节服务的相应方法获取指定课程ID对应的章节树结构数据, + * 将获取到的数据包装在表示成功的Result对象中返回给前端,方便前端根据统一的格式进行解析和展示章节树结构。 + * + * @param courseId 课程的唯一标识符,用于定位要查找章节树的具体课程 + * @return 返回包含章节树结构数据的Result对象,若成功获取则Result对象中的数据字段包含相应的章节树信息,若出现问题则可能包含相应的错误提示等信息 + */ @RequestMapping(value = {"course/findChapterTreeByCourseId"}, method = RequestMethod.GET) @ResponseBody - public Result findChapterTreeByCourseId(String courseId){ + public Result findChapterTreeByCourseId(String courseId) { return Result.successResult(iChapterService.getChapterTree(courseId)); } - -} + +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/FileUploadController.java b/tamguo/src/main/java/com/tamguo/web/FileUploadController.java index 47f678d..1a17e62 100644 --- a/tamguo/src/main/java/com/tamguo/web/FileUploadController.java +++ b/tamguo/src/main/java/com/tamguo/web/FileUploadController.java @@ -24,72 +24,113 @@ import com.tamguo.util.DateUtils; /** * 文件上传 + * 该类作为一个Spring的控制器,主要负责处理文件上传相关的功能,接收前端上传的文件,将其保存到服务器指定的位置,并返回相应的上传结果信息给前端。 */ @RestController public class FileUploadController { - + + // 创建日志记录器,用于记录文件上传过程中的关键信息,例如文件保存的位置、上传是否成功等情况,方便后续查看日志进行调试和问题排查 private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); + + // 通过配置文件注入文件存储路径属性值,指定了服务器上用于存放上传文件的基础路径,后续会根据日期等规则在此基础上构建具体的文件存储目录 @Value("${file.storage.path}") private String fileStoragePath; + + // 自动注入CacheService,用于缓存相关操作,在这里主要是借助缓存来生成具有唯一性且按一定规则递增的文件编号(文件名的一部分) @Autowired private CacheService cacheService; + + // 定义文件编号的默认格式化字符串,用于格式化生成的文件编号,保证编号格式统一,使其具有固定的长度和格式要求 private static final String FILES_NO_FORMAT = "00000"; + // 定义文件编号的前缀,方便识别文件相关的编号,使其在整体文件名中有一定的标识性,便于区分不同类型或用途的文件 private static final String FILES_PREFIX = "FP"; - + + /** + * 处理文件上传的POST请求,接收前端传来的MultipartFile类型的文件,进行文件保存到服务器的操作,若保存成功则返回表示成功的Ueditor对象,包含文件相关信息; + * 若出现异常或文件为空等情况,则返回相应的表示错误的Ueditor对象给前端,告知上传结果。 + * + * @param upfile 前端上传的MultipartFile类型文件,包含了文件的内容以及相关的元数据(如文件名、文件类型等) + * @return 返回Ueditor对象,该对象包含了文件上传的状态(SUCCESS或ERROR)、文件名以及文件在服务器上的访问路径等信息,前端可根据这些信息进行相应的展示或后续处理 + * @throws IOException 如果在文件读写等操作过程中出现I/O异常则抛出,例如读取文件输入流、写入文件输出流时可能出现的异常情况 + */ @RequestMapping(value = "/uploadFile", method = RequestMethod.POST) @ResponseBody - public Ueditor imgUpload(MultipartFile upfile) throws IOException { - if (!upfile.isEmpty()) { + public Ueditor imgUpload(MultipartFile upfile) throws IOException { + // 判断上传的文件是否为空,如果为空则直接返回表示文件为空的错误信息的Ueditor对象给前端 + if (!upfile.isEmpty()) { InputStream in = null; OutputStream out = null; - + try { + // 根据当前日期构建文件存储的路径,将配置的基础存储路径与格式化后的当前日期(格式为yyyyMMdd)拼接起来,方便按日期分类存储文件,便于管理和查找 String path = fileStoragePath + DateUtils.format(new Date(), "yyyyMMdd"); File dir = new File(path); + // 如果目录不存在,则创建相应的目录,确保文件有存储的位置,避免后续保存文件时因目录不存在而出现错误 if (!dir.exists()) dir.mkdirs(); + + // 生成文件名,结合通过缓存获取的文件编号以及原文件名的后缀组成完整的文件名,保证文件名的唯一性以及符合一定的命名规则 String fileName = this.getTeacherNo() + upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")); + // 创建表示服务器上要保存的文件的File对象,指定其完整的保存路径和文件名 File serverFile = new File(dir + File.separator + fileName); + // 获取文件输入流,用于读取上传文件的内容,以便后续将内容写入到服务器的文件中 in = upfile.getInputStream(); + // 创建文件输出流,用于将读取的文件内容写入到服务器指定的存储位置,即上面创建的serverFile所代表的文件中 out = new FileOutputStream(serverFile); + byte[] b = new byte[1024]; int len = 0; + // 通过循环读取输入流中的文件内容,并写入到输出流中,实现文件的复制保存操作,将上传的文件从临时存储位置复制到服务器指定的存储位置 while ((len = in.read(b)) > 0) { out.write(b, 0, len); } + // 关闭输出流,释放相关资源,避免资源泄露 out.close(); + // 关闭输入流,释放相关资源,避免资源泄露 in.close(); + // 记录文件在服务器上的存储位置信息到日志中,方便后续查看和排查问题,例如确认文件是否保存成功以及保存的具体位置是否正确等 logger.info("Server File Location=" + serverFile.getAbsolutePath()); - Ueditor ueditor = new Ueditor(); - ueditor.setState("SUCCESS"); - ueditor.setTitle(upfile.getOriginalFilename()); - ueditor.setUrl("files" + "/" +DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName); - return ueditor; + // 创建表示文件上传成功的Ueditor对象,并设置相应的成功状态、原文件名(作为标题)以及文件在服务器上的访问路径等信息 + Ueditor ueditor = new Ueditor(); + ueditor.setState("SUCCESS"); + ueditor.setTitle(upfile.getOriginalFilename()); + ueditor.setUrl("files" + "/" + DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName); + return ueditor; } catch (Exception e) { + // 如果在文件上传过程中出现异常,创建表示文件上传失败的Ueditor对象,并设置相应的错误状态和提示信息(这里统一设置为"上传失败"),然后返回该对象告知前端上传失败 Ueditor ueditor = new Ueditor(); - ueditor.setState("ERROR"); - ueditor.setTitle("上传失败"); - return ueditor; + ueditor.setState("ERROR"); + ueditor.setTitle("上传失败"); + return ueditor; } finally { - if (out != null) { + // 在最终块中确保输出流资源被正确关闭,避免资源泄露,即使在前面出现异常的情况下也能保证资源的正确释放 + if (out!= null) { out.close(); out = null; } - if (in != null) { + // 在最终块中确保输入流资源被正确关闭,避免资源泄露,即使在前面出现异常的情况下也能保证资源的正确释放 + if (in!= null) { in.close(); in = null; } } } else { + // 如果上传的文件为空,创建表示文件为空的错误的Ueditor对象,并设置相应的错误状态和提示信息,然后返回该对象告知前端文件为空 Ueditor ueditor = new Ueditor(); - ueditor.setState("ERROR"); - ueditor.setTitle("File is empty"); - return ueditor; + ueditor.setState("ERROR"); + ueditor.setTitle("File is empty"); + return ueditor; } - } - + } + + /** + * 生成文件编号的方法,先根据当前日期格式化得到年月格式的字符串作为缓存的键前缀,然后通过缓存服务获取自增的编号,再按照指定格式进行格式化,最后拼接前缀生成完整的文件编号。 + * 这样生成的文件编号具有唯一性且按照一定规则递增,方便对文件进行管理和识别。 + * + * @return 返回生成的文件编号字符串,用于组成文件名的一部分,保证文件名的唯一性和规范性 + */ private String getTeacherNo() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); String format = sdf.format(new Date()); @@ -100,4 +141,4 @@ public class FileUploadController { return avatorNo; } -} +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/IndexController.java b/tamguo/src/main/java/com/tamguo/web/IndexController.java index d3dda61..0d5b2e7 100644 --- a/tamguo/src/main/java/com/tamguo/web/IndexController.java +++ b/tamguo/src/main/java/com/tamguo/web/IndexController.java @@ -5,36 +5,71 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; +// 标识这是一个Spring的控制器类,用于处理不同路径的Web请求,并返回相应的视图给客户端展示不同的页面内容。 @Controller public class IndexController { - - @RequestMapping(value = "/", method = RequestMethod.GET) + + /** + * 处理根路径("/")的GET请求,将视图名称设置为"index",意味着会查找并渲染名为"index"的视图模板(例如JSP、Thymeleaf等模板文件,具体取决于项目配置)返回给客户端, + * 一般用于展示网站的首页内容。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图。 + */ + @RequestMapping(value = "/", method = RequestMethod.GET) public ModelAndView indexAction(ModelAndView model) { - model.setViewName("index"); + model.setViewName("index"); return model; } - + + /** + * 处理"/index"路径的GET请求,同样将视图名称设置为"index",和上面的根路径请求类似,也是用于展示网站的首页内容,可能是为了兼容不同用户访问首页时使用不同的路径形式。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图。 + */ @RequestMapping(value = "/index", method = RequestMethod.GET) public ModelAndView mainAction(ModelAndView model) { - model.setViewName("index"); + model.setViewName("index"); return model; } - + + /** + * 处理"/baidu_verify_5agfTbCO3Q"路径的GET请求,将视图名称设置为"thirdparty/baidu_verify_5agfTbCO3Q", + * 意味着会查找并渲染对应的视图模板(可能是用于百度验证相关的页面,具体取决于业务需求)返回给客户端,用于满足百度相关验证服务对特定页面的要求。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图。 + */ @RequestMapping(value = "/baidu_verify_5agfTbCO3Q", method = RequestMethod.GET) public ModelAndView baidu_verify_5agfTbCO3Q(ModelAndView model) { - model.setViewName("thirdparty/baidu_verify_5agfTbCO3Q"); + model.setViewName("thirdparty/baidu_verify_5agfTbCO3Q"); return model; } - + + /** + * 处理"/baidu_verify_iAm7387J0l"路径的GET请求,将视图名称设置为"thirdparty/baidu_verify_iAm7387J0l", + * 意味着会查找并渲染对应的视图模板(同样可能是用于百度验证相关的页面,具体取决于业务需求)返回给客户端,用于满足百度相关验证服务对特定页面的要求。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图。 + */ @RequestMapping(value = "/baidu_verify_iAm7387J0l", method = RequestMethod.GET) public ModelAndView baidu_verify_iAm7387J0l(ModelAndView model) { - model.setViewName("thirdparty/baidu_verify_iAm7387J0l"); + model.setViewName("thirdparty/baidu_verify_iAm7387J0l"); return model; } - + + /** + * 处理"/sogousiteverification"路径的GET请求,将视图名称设置为"thirdparty/sogousiteverification", + * 意味着会查找并渲染对应的视图模板(可能是用于搜狗网站验证相关的页面,具体取决于业务需求)返回给客户端,用于满足搜狗相关验证服务对特定页面的要求。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图。 + */ @RequestMapping(value = "/sogousiteverification", method = RequestMethod.GET) public ModelAndView sogousiteverification(ModelAndView model) { - model.setViewName("thirdparty/sogousiteverification"); + model.setViewName("thirdparty/sogousiteverification"); return model; } -} +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/LoginController.java b/tamguo/src/main/java/com/tamguo/web/LoginController.java index aece24b..65f5807 100644 --- a/tamguo/src/main/java/com/tamguo/web/LoginController.java +++ b/tamguo/src/main/java/com/tamguo/web/LoginController.java @@ -27,94 +27,176 @@ import com.google.code.kaptcha.Producer; import com.tamguo.util.Result; import com.tamguo.util.ShiroUtils; +// 标识这是一个Spring的控制器类,主要用于处理用户登录相关的Web请求,包括生成验证码、展示登录页面以及处理登录提交等操作。 @Controller public class LoginController { - + + // 自动注入Producer,用于生成验证码相关的操作,比如创建验证码文本和对应的图片验证码。 @Autowired private Producer producer; + /** + * 处理生成验证码图片的请求,该请求对应的路径为 "captcha.jpg",用于生成并返回一个图片格式的验证码给客户端显示。 + * 主要步骤包括设置响应头信息(禁止缓存)、指定响应内容类型为图片(JPEG格式),生成验证码文本和对应的图片, + * 将验证码文本保存到Shiro的会话中以便后续验证,最后将图片通过输出流输出给客户端。 + * + * @param response HttpServletResponse对象,用于设置响应相关的信息,如响应头、输出流等,以便向客户端返回验证码图片。 + * @throws ServletException 如果在Servlet处理过程中出现异常则抛出,例如设置响应头、获取输出流等操作出现问题时可能抛出此异常。 + * @throws IOException 如果在读写图片数据到输出流等I/O操作过程中出现异常则抛出。 + */ @RequestMapping("captcha.jpg") public void captcha(HttpServletResponse response) throws ServletException, IOException { + // 设置响应头,禁止客户端缓存验证码图片,确保每次获取的验证码都是新生成的。 response.setHeader("Cache-Control", "no-store, no-cache"); + // 设置响应的内容类型为JPEG格式的图片,告知客户端返回的数据是图片类型,以便正确解析和显示。 response.setContentType("image/jpeg"); - // 生成文字验证码 + + // 生成验证码的文本内容,通常是由数字、字母等组成的随机字符串,具体生成规则由所使用的验证码生成组件(这里是Producer)决定。 String text = producer.createText(); - // 生成图片验证码 + // 根据生成的验证码文本创建对应的图片验证码,生成的是一个BufferedImage类型的图片对象,包含了验证码文本的可视化表示形式。 BufferedImage image = producer.createImage(text); - // 保存到shiro session + + // 将生成的验证码文本保存到Shiro的会话中,以Constants.KAPTCHA_SESSION_KEY作为键,方便后续在验证用户输入的验证码时从会话中获取并比对。 ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text); + + // 获取ServletResponse的输出流,用于将生成的图片数据写入到响应中,发送给客户端进行显示。 ServletOutputStream out = response.getOutputStream(); + // 使用ImageIO将BufferedImage格式的图片以JPEG格式写入到输出流中,实现将验证码图片返回给客户端的功能。 ImageIO.write(image, "jpg", out); } - + + /** + * 处理登录页面的GET请求,设置视图名称为"login",意味着会查找并渲染名为"login"的视图模板(例如JSP、Thymeleaf等模板文件,具体取决于项目配置)返回给客户端展示登录页面, + * 同时向视图模型中添加一个名为"isVerifyCode",值为"0"的属性,可能用于前端页面判断是否显示验证码相关的逻辑(具体用途根据前端代码确定)。 + * + * @param model 用于传递数据到视图的ModelAndView对象,在这里向其添加了登录页面相关的数据(如是否显示验证码的标识)。 + * @return 返回包含视图名称和相关数据的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图展示给用户。 + */ @RequestMapping(value = "/login", method = RequestMethod.GET) - public ModelAndView login(ModelAndView model){ + public ModelAndView login(ModelAndView model) { model.setViewName("login"); - model.addObject("isVerifyCode" , "0"); + model.addObject("isVerifyCode", "0"); return model; } - + + /** + * 处理用户提交登录信息的POST请求,接收用户名、密码和验证码等参数,进行登录验证相关的一系列操作,包括验证码验证、Shiro框架的登录认证等, + * 根据验证结果设置相应的提示信息,并返回登录页面或者重定向到登录成功后的页面(如果登录成功)。 + * + * @param username 用户输入的用户名,用于登录认证。 + * @param password 用户输入的密码,用于登录认证。 + * @param verifyCode 用户输入的验证码,用于与生成并保存在会话中的验证码进行比对验证。 + * @param model 用于传递数据到视图的ModelAndView对象,根据登录验证结果向其添加相应的提示信息、用户名等数据,以便在登录页面展示给用户。 + * @param session 当前的HttpSession对象,用于获取或设置会话相关的属性,如保存登录后的用户信息等操作。 + * @param response HttpServletResponse对象,用于在登录成功时进行重定向操作,将用户引导到登录成功后的页面。 + * @throws IOException 如果在重定向等操作过程中出现I/O异常则抛出,例如向客户端发送重定向响应时可能出现的异常情况。 + */ @RequestMapping(value = "/submitLogin", method = RequestMethod.POST) - public ModelAndView submitLogin(String username , String password , String verifyCode , ModelAndView model , HttpSession session , HttpServletResponse response) throws IOException{ + public ModelAndView submitLogin(String username, String password, String verifyCode, ModelAndView model, + HttpSession session, HttpServletResponse response) throws IOException { + // 创建一个表示登录结果的Result对象,初始化为成功状态(这里先设置为成功,后续根据实际验证情况进行修改),其内容暂时为空。 Result result = Result.successResult(null); - if(StringUtils.isEmpty(verifyCode)) { + + // 判断用户输入的验证码是否为空,如果为空则表示用户未输入验证码,设置相应的错误提示信息到Result对象中。 + if (StringUtils.isEmpty(verifyCode)) { result = Result.result(202, null, "请输入验证码"); - } else if(StringUtils.isNotEmpty(verifyCode)){ + } else if (StringUtils.isNotEmpty(verifyCode)) { + // 如果用户输入了验证码,从Shiro会话中获取之前生成并保存的验证码文本,用于和用户输入的验证码进行比对验证。 String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY); + // 忽略大小写比较用户输入的验证码和会话中的验证码是否一致,如果不一致则表示验证码错误,设置相应的错误提示信息到Result对象中。 if (!verifyCode.equalsIgnoreCase(kaptcha)) { result = Result.result(205, null, "验证码错误"); } else { + // 如果验证码验证通过,获取Shiro的Subject对象,它代表了当前执行的用户主体,用于后续进行登录认证等操作。 Subject subject = ShiroUtils.getSubject(); + // 创建一个UsernamePasswordToken对象,将用户输入的用户名和密码封装进去,作为登录认证的凭证传递给Shiro框架。 UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { + // 通过Subject对象发起登录认证操作,Shiro框架会根据配置的认证逻辑(如从数据库查询用户信息并比对密码等)进行验证。 subject.login(token); - + + // 如果登录成功,将登录后的用户信息保存到HttpSession中,方便在后续的请求处理中获取当前登录用户的相关信息,键为"currMember"。 session.setAttribute("currMember", ShiroUtils.getMember()); + // 重定向到登录成功后的页面(这里是"member/index.html",可能是会员相关的首页之类的页面,具体根据业务需求确定)。 response.sendRedirect("member/index.html"); + // 登录成功后直接返回null,因为已经进行了重定向操作,不需要再返回视图相关的内容了。 return null; } catch (UnknownAccountException e) { + // 如果Shiro认证过程中抛出UnknownAccountException异常,表示用户名不存在或者未找到对应的用户信息,设置相应的错误提示信息到Result对象中。 result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码"); } catch (IncorrectCredentialsException e) { + // 如果Shiro认证过程中抛出IncorrectCredentialsException异常,表示密码错误,设置相应的错误提示信息到Result对象中。 result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码"); } catch (LockedAccountException e) { + // 如果Shiro认证过程中抛出LockedAccountException异常,表示账号被锁定,设置相应的错误提示信息到Result对象中。 result = Result.result(203, null, "账号被锁定"); - } + } } - } - model.setViewName("login"); + } + + // 如果登录验证未通过(出现各种错误情况),设置视图名称为"login",表示返回登录页面展示给用户相应的错误提示信息。 + model.setViewName("login"); + // 将登录结果的状态码添加到视图模型中,方便前端页面根据状态码进行不同的提示信息展示等逻辑处理。 model.addObject("code", result.getCode()); - model.addObject("msg" , result.getMessage()); + // 将登录结果的提示信息添加到视图模型中,以便在登录页面展示给用户具体的错误原因等内容。 + model.addObject("msg", result.getMessage()); + // 将用户输入的用户名添加到视图模型中,可能用于前端页面保留用户之前输入的用户名,提升用户体验等用途(具体根据前端需求确定)。 model.addObject("username", username); return model; } - + + /** + * 处理小型登录(可能是用于移动端或者特定场景下简化的登录方式)的GET请求,接收用户名、密码和验证码等参数,进行登录验证相关的一系列操作, + * 根据验证结果返回相应的Result对象,包含登录成功后的用户信息(如果登录成功)或者错误提示信息(如果登录失败)。 + * 与submitLogin方法类似,也进行了验证码验证、Shiro框架的登录认证以及各种异常情况的处理,但这里是通过ResponseBody注解直接返回Result对象给客户端,而不是返回视图相关内容。 + * + * @param username 用户输入的用户名,用于登录认证。 + * @param password 用户输入的密码,用于登录认证。 + * @param captcha 用户输入的验证码,用于与生成并保存在会话中的验证码进行比对验证。 + * @param model 用于传递数据到视图的ModelAndView对象(这里在该方法中未实际使用到,可能是为了与其他类似方法保持参数形式一致而添加的)。 + * @param session 当前的HttpSession对象,用于获取或设置会话相关的属性,如保存登录后的用户信息等操作。 + * @return 返回表示登录结果的Result对象,包含登录成功后的用户信息或者相应的错误提示信息,客户端可根据返回结果进行后续的处理,如展示提示信息或者跳转到相应页面等。 + */ @RequestMapping(value = "/miniLogin", method = RequestMethod.GET) @ResponseBody - public Result miniLogin(String username , String password , String captcha, ModelAndView model , HttpSession session) { + public Result miniLogin(String username, String password, String captcha, ModelAndView model, + HttpSession session) { Result result = null; - if(StringUtils.isEmpty(captcha)) { + // 判断用户输入的验证码是否为空,如果为空则表示用户未输入验证码,设置相应的错误提示信息到Result对象中。 + if (StringUtils.isEmpty(captcha)) { result = Result.result(204, null, "请输入验证码"); - } else if(StringUtils.isNotEmpty(captcha)){ + } else if (StringUtils.isNotEmpty(captcha)) { + // 如果用户输入了验证码,从Shiro会话中获取之前生成并保存的验证码文本,用于和用户输入的验证码进行比对验证。 String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY); + // 忽略大小写比较用户输入的验证码和会话中的验证码是否一致,如果不一致则表示验证码错误,设置相应的错误提示信息到Result对象中。 if (!captcha.equalsIgnoreCase(kaptcha)) { result = Result.result(205, null, "验证码错误"); - }else { + } else { + // 如果验证码验证通过,获取Shiro的Subject对象,它代表了当前执行的用户主体,用于后续进行登录认证等操作。 Subject subject = ShiroUtils.getSubject(); + // 创建一个UsernamePasswordToken对象,将用户输入的用户名和密码封装进去,作为登录认证的凭证传递给Shiro框架。 UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { + // 通过Subject对象发起登录认证操作,Shiro框架会根据配置的认证逻辑(如从数据库查询用户信息并比对密码等)进行验证。 subject.login(token); + + // 如果登录成功,将登录后的用户信息保存到HttpSession中,方便在后续的请求处理中获取当前登录用户的相关信息,键为"currMember"。 session.setAttribute("currMember", ShiroUtils.getMember()); + // 创建表示登录成功的Result对象,并将登录后的用户信息设置到Result对象中,以便返回给客户端。 result = Result.successResult(ShiroUtils.getMember()); } catch (UnknownAccountException e) { + // 如果Shiro认证过程中抛出UnknownAccountException异常,表示用户名不存在或者未找到对应的用户信息,设置相应的错误提示信息到Result对象中。 result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码"); } catch (IncorrectCredentialsException e) { + // 如果Shiro认证过程中抛出IncorrectCredentialsException异常,表示密码错误,设置相应的错误提示信息到Result对象中。 result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码"); } catch (LockedAccountException e) { + // 如果Shiro认证过程中抛出LockedAccountException异常,表示账号被锁定,设置相应的错误提示信息到Result对象中。 result = Result.result(203, null, "账号被锁定"); - } + } } } return result; - } + } -} +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/PaperController.java b/tamguo/src/main/java/com/tamguo/web/PaperController.java index 2c26b6d..020913b 100644 --- a/tamguo/src/main/java/com/tamguo/web/PaperController.java +++ b/tamguo/src/main/java/com/tamguo/web/PaperController.java @@ -25,84 +25,191 @@ import com.tamguo.util.TamguoConstant; /** * Controller - 试卷 - * - * @author candy.tam + * 该类作为Spring的控制器,主要用于处理与试卷相关的各种Web请求,例如展示试卷列表页面、试卷详情页面,以及根据地区查找试卷等功能, + * 通过调用相应的服务层接口获取数据,并将数据添加到ModelAndView对象中返回给视图进行展示,或者直接以JSON格式返回数据给前端(如通过@ResponseBody注解的方法)。 * + * @author candy.tam */ @Controller public class PaperController { - + + // 自动注入ICourseService,用于处理课程相关的业务逻辑,比如根据课程ID查找课程、按学科ID查找课程列表等操作,在获取试卷相关信息时可能会涉及课程信息的查询。 @Autowired private ICourseService iCourseService; + + // 自动注入IAreaService,用于处理地区相关的业务逻辑,例如查找根地区列表等操作,可能在按地区筛选试卷等功能中会用到地区相关信息的查询。 @Autowired private IAreaService iAreaService; + + // 自动注入IPaperService,用于处理试卷相关的业务逻辑,像查找试卷、获取试卷列表、根据各种条件筛选试卷、获取推荐试卷等操作都是通过该服务来完成。 @Autowired private IPaperService iPaperService; + + // 自动注入IQuestionService,用于处理试题相关的业务逻辑,例如查找试卷对应的试题列表等操作,在试卷详情页面展示试题信息时会调用该服务。 @Autowired private IQuestionService iQuestionService; + + // 自动注入ISubjectService,用于处理学科相关的业务逻辑,例如根据学科ID查找学科信息等操作,试卷通常与特定学科相关,查询试卷相关信息时可能需要获取学科相关内容。 @Autowired private ISubjectService iSubjectService; + /** + * 处理试卷列表页面的GET请求,根据传入的多个路径变量(学科ID、课程ID、试卷类型、年份、地区、页码),查询并获取与这些条件相关的试卷列表及其他相关信息(如课程、学科、地区列表等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"paperlist",最后返回该ModelAndView对象用于渲染相应的试卷列表页面视图给用户。 + * 如果在查询过程中出现异常,则将视图名称设置为"404",返回相应的ModelAndView对象,表示出现错误情况(可能展示404页面给用户)。 + * + * @param subjectId 学科的唯一标识符,用于筛选特定学科下的试卷列表。 + * @param courseId 课程的唯一标识符,用于进一步筛选属于该课程的试卷。 + * @param paperType 试卷的类型,用于按类型筛选试卷(具体类型值根据业务定义,可能是真题、模拟题等分类)。 + * @param year 试卷对应的年份,用于按年份筛选试卷,方便用户查找特定年份的试卷。 + * @param area 试卷所属的地区,用于按地区筛选试卷,满足不同地区用户查看对应地区试卷的需求。 + * @param pageNum 当前页码,用于分页查询试卷列表,确定要展示的那一页试卷信息。 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中。 + * @return 返回包含视图名称和相关试卷及关联数据的ModelAndView对象,用于渲染相应的试卷列表页面视图。 + */ @RequestMapping(value = {"paperlist/{subjectId}-{courseId}-{paperType}-{year}-{area}-{pageNum}"}, method = RequestMethod.GET) - public ModelAndView indexAction(@PathVariable String subjectId , @PathVariable String courseId , @PathVariable String paperType, - @PathVariable String year , @PathVariable String area , @PathVariable Integer pageNum, ModelAndView model) { - try { - model.setViewName("paperlist"); - - CourseEntity course = iCourseService.find(courseId); - List courseList = iCourseService.findBySubjectId(subjectId); - SubjectEntity subject = iSubjectService.find(subjectId); - List areaList = iAreaService.findRootArea(); - PageUtils page = PageUtils.getPage(iPaperService.findList(subjectId , courseId , paperType , year , area , pageNum)); - if(course == null) { - course = courseList.get(0); - } - Long total = iPaperService.getPaperTotal(); - model.addObject("courseList", courseList); - model.addObject("subject", subject); - model.addObject("course", course); - model.addObject("areaList", areaList); - model.addObject("paperPage" , page); - model.addObject("total" , total); - model.addObject("courseId", course.getUid()); - model.addObject("paperType", paperType); - model.addObject("year", year); - model.addObject("area", area); - return model; + public ModelAndView indexAction(@PathVariable String subjectId, @PathVariable String courseId, + @PathVariable String paperType, @PathVariable String year, @PathVariable String area, + @PathVariable Integer pageNum, ModelAndView model) { + try { + // 设置视图名称为"paperlist",对应相应的试卷列表页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。 + model.setViewName("paperlist"); + + // 根据传入的课程ID,通过课程服务查询并获取对应的课程实体信息,用于在试卷列表页面展示试卷所属课程等相关信息。 + CourseEntity course = iCourseService.find(courseId); + + // 通过课程服务,查找与传入学科ID对应的所有课程列表,可能用于在试卷列表页面展示该学科下的所有课程,方便用户切换查看不同课程的试卷情况。 + List courseList = iCourseService.findBySubjectId(subjectId); + + // 根据传入的学科ID,通过学科服务查询并获取对应的学科实体信息,用于在试卷列表页面展示试卷所属学科等相关信息。 + SubjectEntity subject = iSubjectService.find(subjectId); + + // 通过地区服务查找根地区列表信息,可能用于在试卷列表页面提供地区筛选的下拉菜单等功能,展示所有可选的地区范围(具体根据业务需求而定)。 + List areaList = iAreaService.findRootArea(); + + // 调用试卷服务的findList方法,根据传入的多个条件(学科ID、课程ID、试卷类型、年份、地区、页码)获取相应的试卷列表数据,并通过PageUtils工具类进行分页相关的处理,得到包含分页信息的PageUtils对象。 + PageUtils page = PageUtils.getPage(iPaperService.findList(subjectId, courseId, paperType, year, area, pageNum)); + + // 如果通过课程ID未查询到对应的课程实体(可能课程ID不存在或者其他原因导致查询失败),则取课程列表中的第一个课程作为默认展示(具体根据业务逻辑需求调整)。 + if (course == null) { + course = courseList.get(0); + } + + // 调用试卷服务的getPaperTotal方法获取试卷的总数量,可能用于在试卷列表页面展示总共有多少试卷等相关统计信息。 + Long total = iPaperService.getPaperTotal(); + + // 将查询到的课程列表信息添加到ModelAndView对象中,以便在视图中展示该学科下的所有课程情况,方便用户切换查看不同课程的试卷。 + model.addObject("courseList", courseList); + + // 将查询到的学科实体信息添加到ModelAndView对象中,以便在视图中展示试卷所属学科等相关信息。 + model.addObject("subject", subject); + + // 将查询到的课程实体信息添加到ModelAndView对象中,以便在视图中展示试卷所属课程等相关信息。 + model.addObject("course", course); + + // 将查询到的地区列表信息添加到ModelAndView对象中,以便在视图中展示可筛选的地区范围,供用户按地区查找试卷。 + model.addObject("areaList", areaList); + + // 将包含分页信息的试卷列表数据(通过PageUtils包装)添加到ModelAndView对象中,以便在视图中展示具体的试卷列表内容。 + model.addObject("paperPage", page); + + // 将试卷的总数量添加到ModelAndView对象中,以便在视图中展示试卷的统计信息,如告知用户总共有多少试卷等。 + model.addObject("total", total); + + // 将当前试卷所属的课程ID添加到ModelAndView对象中,可能用于前端页面的一些交互逻辑或者链接生成等用途(具体根据前端需求确定)。 + model.addObject("courseId", course.getUid()); + + // 将当前试卷的类型添加到ModelAndView对象中,可能用于在视图中对试卷进行分类展示或者筛选等相关操作(具体根据前端展示需求确定)。 + model.addObject("paperType", paperType); + + // 将当前试卷对应的年份添加到ModelAndView对象中,可能用于在视图中按年份对试卷进行筛选或者展示等相关操作(具体根据前端展示需求确定)。 + model.addObject("year", year); + + // 将当前试卷所属的地区添加到ModelAndView对象中,可能用于在视图中按地区对试卷进行筛选或者展示等相关操作(具体根据前端展示需求确定)。 + model.addObject("area", area); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户试卷列表页面内容。 + return model; } catch (Exception e) { + // 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。 model.setViewName("404"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出404页面展示给用户。 return model; } - - } - + + } + + /** + * 处理试卷详情页面的GET请求,根据传入的试卷ID,查询并获取与该试卷相关的各种信息(如试卷本身信息、所属学科、课程、试题列表以及各种推荐试卷列表等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"paper",最后返回该ModelAndView对象用于渲染相应的试卷详情页面视图给用户。 + * 如果在查询过程中出现异常,则将视图名称设置为"404",返回相应的ModelAndView对象,表示出现错误情况(可能展示404页面给用户)。 + * + * @param paperId 试卷的唯一标识符,用于定位要展示详情的具体试卷。 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中。 + * @return 返回包含视图名称和相关试卷及关联数据的ModelAndView对象,用于渲染相应的试卷详情页面视图。 + */ @RequestMapping(value = {"/paper/{paperId}.html"}, method = RequestMethod.GET) - public ModelAndView indexAction(@PathVariable String paperId , ModelAndView model){ + public ModelAndView indexAction(@PathVariable String paperId, ModelAndView model) { try { + // 设置视图名称为"paper",对应相应的试卷详情页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。 model.setViewName("paper"); + + // 根据传入的试卷ID,通过试卷服务查询并获取对应的试卷实体信息,用于在试卷详情页面展示试卷的详细内容。 PaperEntity paper = iPaperService.find(paperId); + + // 将查询到的试卷实体信息添加到ModelAndView对象中,以便在视图中展示试卷的详细内容,如试卷名称、考试时间等信息。 model.addObject("paper", paper); - model.addObject("subject", StringUtils.isEmpty(paper.getSubjectId()) ? null : iSubjectService.find(paper.getSubjectId())); - model.addObject("course", StringUtils.isEmpty(paper.getCourseId()) ? null : iCourseService.find(paper.getCourseId())); + + // 判断试卷的学科ID是否为空,如果不为空则通过学科服务查询并获取对应的学科实体信息,然后添加到ModelAndView对象中,用于在试卷详情页面展示试卷所属学科等相关信息; + // 如果学科ID为空,则添加null,表示没有对应的学科信息(这种情况可能是数据异常等原因导致,具体根据业务逻辑处理)。 + model.addObject("subject", StringUtils.isEmpty(paper.getSubjectId())? null : iSubjectService.find(paper.getSubjectId())); + + // 判断试卷的课程ID是否为空,如果不为空则通过课程服务查询并获取对应的课程实体信息,然后添加到ModelAndView对象中,用于在试卷详情页面展示试卷所属课程等相关信息; + // 如果课程ID为空,则添加null,表示没有对应的课程信息(这种情况可能是数据异常等原因导致,具体根据业务逻辑处理)。 + model.addObject("course", StringUtils.isEmpty(paper.getCourseId())? null : iCourseService.find(paper.getCourseId())); + + // 通过试题服务,查找该试卷对应的试题列表信息,用于在试卷详情页面展示试卷包含的具体试题内容等情况。 model.addObject("questionList", iQuestionService.findPaperQuestion(paperId)); - // 获取推荐试卷 + // 获取真题推荐试卷列表,调用试卷服务的featuredPaper方法,传入特定的真题标识(TamguoConstant.ZHENGTI_PAPER_ID)和当前试卷的学科ID,获取相关的真题推荐试卷列表, + // 并添加到ModelAndView对象中,用于在试卷详情页面展示相关的推荐试卷内容,方便用户查看其他类似的真题试卷。 model.addObject("zhentiPaperList", iPaperService.featuredPaper(TamguoConstant.ZHENGTI_PAPER_ID, paper.getSubjectId())); + + // 获取模拟题推荐试卷列表,调用试卷服务的featuredPaper方法,传入特定的模拟题标识(TamguoConstant.MONI_PAPER_ID)和当前试卷的学科ID,获取相关的模拟题推荐试卷列表, + // 并添加到ModelAndView对象中,用于在试卷详情页面展示相关的推荐试卷内容,方便用户查看其他类似的模拟题试卷。 model.addObject("moniPaperList", iPaperService.featuredPaper(TamguoConstant.MONI_PAPER_ID, paper.getSubjectId())); + + // 获取押题推荐试卷列表,调用试卷服务的featuredPaper方法,传入特定的押题标识(TamguoConstant.YATI_PAPER_ID)和当前试卷的学科ID,获取相关的押题推荐试卷列表, + // 并添加到ModelAndView对象中,用于在试卷详情页面展示相关的推荐试卷内容,方便用户查看其他类似的押题试卷。 model.addObject("yatiPaperList", iPaperService.featuredPaper(TamguoConstant.YATI_PAPER_ID, paper.getSubjectId())); + + // 获取热门试卷列表,调用试卷服务的findHotPaper方法,传入当前试卷的学科ID和课程ID,获取相关的热门试卷列表, + // 并添加到ModelAndView对象中,用于在试卷详情页面展示相关的推荐试卷内容,方便用户查看其他热门的试卷。 model.addObject("hotPaperList", iPaperService.findHotPaper(paper.getSubjectId(), paper.getCourseId())); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户试卷详情页面内容。 return model; } catch (Exception e) { + // 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。 model.setViewName("404"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出404页面展示给用户。 return model; } - + } - + + /** + * 处理根据地区ID和试卷类型查找试卷的GET请求,直接调用试卷服务的相应方法,根据传入的地区ID和试卷类型查找对应的试卷列表信息,并将查找结果(试卷列表)以JSON格式返回给前端, + * 方便前端根据返回的试卷数据进行展示或者其他相关操作(例如动态加载某个地区下特定类型的试卷列表等功能)。 + * + * @param areaId 地区的唯一标识符,用于定位要查找试卷所属的地区范围。 + * @param type 试卷的类型,用于筛选出符合该类型的试卷,具体类型值根据业务定义,可能是真题、模拟题等分类。 + * @return 返回包含指定地区下符合类型要求的所有试卷实体信息的List列表,若未找到则返回空列表,前端可根据返回结果进行相应展示或处理。 + */ @RequestMapping(value = {"/paper/area/{areaId}-{type}.html"}, method = RequestMethod.GET) @ResponseBody - public List findPaperByAreaId(@PathVariable String areaId ,@PathVariable String type){ - return iPaperService.findPaperByAreaId(areaId , type); + public List findPaperByAreaId(@PathVariable String areaId, @PathVariable String type) { + return iPaperService.findPaperByAreaId(areaId, type); } - -} + +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/PasswordController.java b/tamguo/src/main/java/com/tamguo/web/PasswordController.java index cae68a2..9779553 100644 --- a/tamguo/src/main/java/com/tamguo/web/PasswordController.java +++ b/tamguo/src/main/java/com/tamguo/web/PasswordController.java @@ -10,66 +10,147 @@ import org.springframework.web.servlet.ModelAndView; import com.tamguo.service.IMemberService; import com.tamguo.util.Result; +// 标识这是一个Spring的控制器类,主要用于处理与用户密码相关的各种操作的Web请求,例如确认账号、安全验证、重置密码以及检查账号是否存在等功能。 @Controller public class PasswordController { - + + // 自动注入IMemberService,用于调用会员相关的业务逻辑方法,比如确认账号、进行安全检查、重置密码以及检查账号有效性等操作,这些操作都依赖于会员服务层提供的具体实现。 @Autowired private IMemberService iMemberService; - + + /** + * 处理密码找回流程中确认账号页面的GET请求,设置视图名称为"password/confirmAccount",意味着会查找并渲染名为"password/confirmAccount"的视图模板(例如JSP、Thymeleaf等模板文件,具体取决于项目配置)返回给客户端展示确认账号页面。 + * 该页面通常用于用户输入账号相关信息(如用户名等)以开始密码找回流程的第一步操作。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据,用于后续视图渲染展示确认账号页面。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图展示给用户。 + */ @RequestMapping(value = "password/find", method = RequestMethod.GET) - public ModelAndView confirmAccount(ModelAndView model){ + public ModelAndView confirmAccount(ModelAndView model) { model.setViewName("password/confirmAccount"); return model; } - + + /** + * 处理密码找回流程中提交确认账号信息的POST请求,接收用户名(username)和验证码(veritycode)参数,调用会员服务的confirmAccount方法进行账号确认相关的业务逻辑处理, + * 根据返回的Result对象中的状态码(code)来决定下一步要展示的页面以及向视图模型中添加的数据内容,比如验证成功则跳转到安全检查页面,失败则返回确认账号页面并展示相应的错误提示信息。 + * + * @param username 用户输入的用户名,用于在会员服务中进行账号确认操作,判断账号是否存在以及验证码是否匹配等情况。 + * @param veritycode 用户输入的验证码,用于与系统生成并发送给用户(可能通过邮箱或短信等方式)的验证码进行比对验证,作为账号确认的一部分依据。 + * @param model 用于传递数据到视图的ModelAndView对象,根据业务逻辑处理结果向其添加相应的数据(如验证结果、账号信息、错误码等),以便在相应的页面展示给用户。 + * @return 返回包含视图名称和相关数据的ModelAndView对象,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户,展示的页面根据业务逻辑验证结果而定(成功跳转到安全检查页面,失败返回确认账号页面)。 + */ @RequestMapping(value = "password/confirmAccount", method = RequestMethod.POST) - public ModelAndView submitConfirmAccount(String username , String veritycode , ModelAndView model){ + public ModelAndView submitConfirmAccount(String username, String veritycode, ModelAndView model) { + // 调用会员服务的confirmAccount方法,传入用户名和验证码进行账号确认操作,返回包含操作结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容。 Result result = iMemberService.confirmAccount(username, veritycode); - if(result.getCode() == 200){ + + // 判断返回的Result对象中的状态码是否为200,表示账号确认操作成功,通常意味着账号存在且验证码匹配等情况符合预期。 + if (result.getCode() == 200) { + // 如果账号确认成功,设置视图名称为"password/securityCheck",表示要跳转到密码找回流程中的安全检查页面,用于后续进一步验证用户身份等操作。 model.setViewName("password/securityCheck"); + // 将确认账号操作返回的Result对象添加到视图模型中,可能在安全检查页面会展示一些相关的提示信息或者使用其中的数据(具体根据前端页面需求确定)。 model.addObject("result", result); - model.addObject("isEmail", username.contains("@") ? "1" : "0"); - }else{ + // 根据用户名中是否包含"@"符号来判断是邮箱账号还是手机号等其他形式账号,将判断结果("1"表示邮箱账号,"0"表示非邮箱账号)添加到视图模型中, + // 可能用于安全检查页面根据账号类型进行不同的验证方式展示等逻辑处理(例如邮箱账号可能通过邮件验证,手机号账号可能通过短信验证等,具体根据业务逻辑确定)。 + model.addObject("isEmail", username.contains("@")? "1" : "0"); + } else { + // 如果账号确认失败,设置视图名称为"password/confirmAccount",表示返回确认账号页面,以便用户重新输入正确的信息进行账号确认操作。 model.setViewName("password/confirmAccount"); + // 将用户输入的账号信息添加到视图模型中,可能用于前端页面保留用户之前输入的账号内容,方便用户查看和修改,提升用户体验。 model.addObject("account", username); - model.addObject("username",username); + // 将用户输入的用户名添加到视图模型中,可能同样用于前端页面保留用户名信息,具体根据前端页面展示需求确定。 + model.addObject("username", username); + // 将用户输入的验证码添加到视图模型中,可能用于前端页面展示用户之前输入的验证码内容,方便用户查看是否输入有误等情况。 model.addObject("veritycode", veritycode); + // 将操作失败返回的Result对象中的状态码添加到视图模型中,方便前端页面根据状态码进行不同的错误提示信息展示等逻辑处理,告知用户具体是哪种验证失败的情况。 model.addObject("code", result.getCode()); } + + // 返回包含视图名称和相应数据的ModelAndView对象,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户。 return model; } - + + /** + * 处理密码找回流程中安全检查的POST请求,接收用户名(username)、是否为邮箱账号标识(isEmail)以及手机验证码(mobileVcode)等参数,调用会员服务的securityCheck方法进行安全检查相关的业务逻辑处理, + * 根据返回的Result对象中的状态码(code)来决定下一步要展示的页面以及向视图模型中添加的数据内容,比如验证成功则跳转到重置密码页面并传递相关数据,失败则返回安全检查页面并展示相应的错误提示信息。 + * + * @param username 用户输入的用户名,用于在会员服务中进一步确认用户身份等相关安全检查操作,确保是合法的用户进行密码重置操作。 + * @param isEmail 表示账号是否为邮箱账号的标识,从前端传递过来,用于在会员服务中根据账号类型进行不同的安全检查逻辑处理(例如邮箱账号可能验证邮件验证码,手机号账号可能验证短信验证码等),值为"1"表示是邮箱账号,"0"表示不是邮箱账号。 + * @param mobileVcode 用户输入的手机验证码(如果是手机号账号相关验证场景),用于与系统发送给用户手机的验证码进行比对验证,作为安全检查的一部分依据;如果是邮箱账号相关验证场景,此处可能根据业务逻辑不一定使用该参数(具体依实际情况而定)。 + * @param model 用于传递数据到视图的ModelAndView对象,根据业务逻辑处理结果向其添加相应的数据(如用户名、重置密码的关键信息、验证结果、错误标识等),以便在相应的页面展示给用户。 + * @return 返回包含视图名称和相关数据的ModelAndView对象,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户,展示的页面根据业务逻辑验证结果而定(成功跳转到重置密码页面,失败返回安全检查页面)。 + */ @RequestMapping(value = "password/securityCheck", method = RequestMethod.POST) - public ModelAndView securityCheck(String username , String isEmail , String mobileVcode , ModelAndView model){ - Result result = iMemberService.securityCheck(username , isEmail , mobileVcode); - if(result.getCode() == 200){ + public ModelAndView securityCheck(String username, String isEmail, String mobileVcode, ModelAndView model) { + // 调用会员服务的securityCheck方法,传入用户名、是否为邮箱账号标识以及手机验证码等参数进行安全检查操作,返回包含操作结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容。 + Result result = iMemberService.securityCheck(username, isEmail, mobileVcode); + + // 判断返回的Result对象中的状态码是否为200,表示安全检查操作成功,通常意味着用户身份验证通过等情况符合预期,可以进行下一步的密码重置操作。 + if (result.getCode() == 200) { + // 将用户名添加到视图模型中,可能在重置密码页面会展示用户名等相关信息,告知用户当前正在重置哪个账号的密码(具体根据前端页面需求确定)。 model.addObject("username", username); - model.addObject("resetPasswordKey" , result.getResult()); + // 将安全检查操作成功后返回的Result对象中包含的用于重置密码的关键信息(例如重置密码的令牌等,具体根据业务逻辑确定)添加到视图模型中, + // 后续在重置密码页面会使用该信息来确保是经过安全验证后的合法操作,用于关联和验证密码重置请求。 + model.addObject("resetPasswordKey", result.getResult()); + // 设置视图名称为"password/resetPassword",表示要跳转到密码找回流程中的重置密码页面,用于用户输入新的密码等操作。 model.setViewName("password/resetPassword"); - }else{ + } else { + // 如果安全检查失败,将安全检查操作返回的Result对象添加到视图模型中,可能在安全检查页面会展示一些相关的错误提示信息或者使用其中的数据(具体根据前端页面需求确定)。 model.addObject("result", result); + // 将是否为邮箱账号的标识添加到视图模型中,可能用于安全检查页面根据账号类型进行不同的错误提示信息展示等逻辑处理,告知用户具体是哪种账号类型的验证失败情况。 model.addObject("isEmail", isEmail); + // 添加一个表示验证码错误的标识(值为"1")到视图模型中,方便前端页面根据该标识进行相应的错误提示信息展示,告知用户验证码输入有误等情况(具体根据前端页面展示逻辑确定)。 model.addObject("codeError", "1"); + // 设置视图名称为"password/securityCheck",表示返回安全检查页面,以便用户重新输入正确的信息进行安全检查操作。 model.setViewName("password/securityCheck"); } + + // 返回包含视图名称和相应数据的ModelAndView对象,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户。 return model; } - + + /** + * 处理密码找回流程中提交重置密码信息的POST请求,接收重置密码的关键信息(resetPasswordKey)、用户名(username)、新密码(password)以及确认新密码(verifypwd)等参数, + * 调用会员服务的resetPassword方法进行密码重置相关的业务逻辑处理,根据返回的Result对象中的状态码(code)来决定下一步要展示的页面(成功则跳转到密码重置成功页面,失败则返回重置密码页面)。 + * + * @param resetPasswordKey 用于验证密码重置操作合法性的关键信息,在前面的安全检查步骤中获取并传递过来,确保当前的密码重置请求是经过合法验证后的操作,防止非法重置密码的情况发生。 + * @param username 用户输入的用户名,用于再次确认是对哪个账号进行密码重置操作,确保操作的准确性和对应性。 + * @param password 用户输入的新密码,用于设置为账号的新密码,在会员服务中会对新密码进行格式等相关验证以及更新到数据库等操作。 + * @param verifypwd 用户输入的确认新密码,用于与新密码进行比对,确保用户两次输入的密码一致,避免因输入错误导致密码不一致的情况。 + * @param model 用于传递数据到视图的ModelAndView对象,根据业务逻辑处理结果向其添加相应的视图名称,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户,展示的页面根据密码重置操作的验证结果而定(成功跳转到密码重置成功页面,失败返回重置密码页面)。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户,展示的页面根据密码重置操作的验证结果而定(成功跳转到密码重置成功页面,失败返回重置密码页面)。 + */ @RequestMapping(value = "password/resetPassword", method = RequestMethod.POST) - public ModelAndView resetPassword(String resetPasswordKey , String username , String password , String verifypwd , ModelAndView model){ - Result result = iMemberService.resetPassword(resetPasswordKey , username , password , verifypwd); - if(result.getCode() == 200){ + public ModelAndView resetPassword(String resetPasswordKey, String username, String password, String verifypwd, + ModelAndView model) { + // 调用会员服务的resetPassword方法,传入重置密码关键信息、用户名、新密码以及确认新密码等参数进行密码重置操作,返回包含操作结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容。 + Result result = iMemberService.resetPassword(resetPasswordKey, username, password, verifypwd); + + // 判断返回的Result对象中的状态码是否为200,表示密码重置操作成功,通常意味着新密码设置成功等情况符合预期。 + if (result.getCode() == 200) { + // 如果密码重置成功,设置视图名称为"password/resetPwSuccess",表示要跳转到密码找回流程中的密码重置成功页面,用于告知用户密码重置操作已顺利完成。 model.setViewName("password/resetPwSuccess"); - }else{ + } else { + // 如果密码重置失败,设置视图名称为"password/resetPassword",表示返回重置密码页面,以便用户重新输入正确的密码信息进行密码重置操作。 model.setViewName("password/resetPassword"); } + + // 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户。 return model; } - + + /** + * 处理检查账号是否存在的GET请求,接收账号信息(account),调用会员服务的checkAccount方法进行账号检查相关的业务逻辑处理,然后直接将返回的Result对象(包含账号存在与否等相关检查结果信息)返回给前端, + * 前端可根据返回的Result对象进行相应的展示或后续处理,例如根据账号是否存在来决定是否显示某些提示信息或者进行下一步操作等。 + * + * @param account 要检查的账号信息,可能是用户名、邮箱账号或者手机号等形式,具体根据业务逻辑中对账号的定义来确定,用于在会员服务中查询判断该账号是否已经存在于系统中。 + * @return 返回包含账号检查结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容,前端可根据这些信息进行相应的处理和展示。 + */ @RequestMapping(value = "password/checkAccount", method = RequestMethod.GET) @ResponseBody - public Result checkAccount(String account){ + public Result checkAccount(String account) { return iMemberService.checkAccount(account); } - -} + +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/QuestionContrller.java b/tamguo/src/main/java/com/tamguo/web/QuestionContrller.java index a62c663..ed16f6c 100644 --- a/tamguo/src/main/java/com/tamguo/web/QuestionContrller.java +++ b/tamguo/src/main/java/com/tamguo/web/QuestionContrller.java @@ -10,6 +10,7 @@ import org.springframework.web.servlet.ModelAndView; import com.baomidou.mybatisplus.plugins.Page; import com.tamguo.model.ChapterEntity; +import com.baomidou.mybatisplus.plugins.Page; import com.tamguo.model.CourseEntity; import com.tamguo.model.QuestionEntity; import com.tamguo.model.SubjectEntity; @@ -20,78 +21,156 @@ import com.tamguo.service.IQuestionService; import com.tamguo.service.ISubjectService; import com.tamguo.util.Result; +// 标识这是一个Spring的控制器类,主要用于处理与试题相关的各种Web请求,例如展示试题列表页面、试题详情页面以及获取特定试题信息等功能, +// 通过调用相应的服务层接口获取数据,并将数据添加到ModelAndView对象中返回给视图进行展示,或者直接以JSON格式返回数据给前端(如通过@ResponseBody注解的方法)。 @Controller public class QuestionContrller { + // 自动注入IQuestionService,用于处理试题相关的业务逻辑,像根据章节ID获取试题列表、查找普通试题、获取推荐试题、按ID选择试题等操作都是通过该服务来完成。 @Autowired private IQuestionService iQuestionService; + + // 自动注入IChapterService,用于处理章节相关的业务逻辑,例如根据章节ID查找章节、查找下一个章节、获取章节所属课程等操作,在获取试题相关信息时可能会涉及章节信息的查询。 @Autowired private IChapterService iChapterService; + + // 自动注入ISubjectService,用于处理学科相关的业务逻辑,例如根据课程所属学科ID查找学科信息等操作,试题通常与特定学科相关,查询试题相关信息时可能需要获取学科相关内容。 @Autowired private ISubjectService iSubjectService; + + // 自动注入ICourseService,用于处理课程相关的业务逻辑,比如根据章节所属课程ID查找课程、获取课程所属学科等操作,在获取试题相关信息时可能会涉及课程信息的查询。 @Autowired private ICourseService iCourseService; - + + /** + * 处理试题列表页面的GET请求,根据传入的章节ID、偏移量(offset,通常用于分页表示起始位置)和每页数量(limit)等路径变量, + * 查询并获取与该章节相关的试题列表及其他相关信息(如章节、课程、学科、父章节、下一个章节等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"questionList",最后返回该ModelAndView对象用于渲染相应的试题列表页面视图给用户。 + * 如果在查询过程中出现异常,则将视图名称设置为"404",返回相应的ModelAndView对象,表示出现错误情况(可能展示404页面给用户)。 + * + * @param chapterId 章节的唯一标识符,用于筛选特定章节下的试题列表,定位到具体属于哪个章节的试题。 + * @param offset 当前页码对应的偏移量,用于分页查询,确定从哪条记录开始获取试题列表,通常结合每页数量来实现分页功能。 + * @param limit 每页显示的试题数量,用于分页查询,确定每页展示多少条试题信息。 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中。 + * @return 返回包含视图名称和相关试题及关联数据的ModelAndView对象,用于渲染相应的试题列表页面视图。 + */ @RequestMapping(value = {"questionlist/{chapterId}-{offset}-{limit}"}, method = RequestMethod.GET) - public ModelAndView questionList(@PathVariable String chapterId , @PathVariable Integer offset , - @PathVariable Integer limit , ModelAndView model){ + public ModelAndView questionList(@PathVariable String chapterId, @PathVariable Integer offset, + @PathVariable Integer limit, ModelAndView model) { try { + // 设置视图名称为"questionList",对应相应的试题列表页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。 model.setViewName("questionList"); + // 根据传入的章节ID,通过章节服务查询并获取对应的章节实体信息,用于在试题列表页面展示试题所属章节等相关信息。 ChapterEntity chapter = iChapterService.findById(chapterId); + + // 通过章节所属的课程ID,利用课程服务查询并获取对应的课程实体信息,用于在试题列表页面展示试题所属课程等相关信息。 CourseEntity course = iCourseService.find(chapter.getCourseId()); + + // 通过课程所属的学科ID,利用学科服务查询并获取对应的学科实体信息,用于在试题列表页面展示试题所属学科等相关信息。 SubjectEntity subject = iSubjectService.find(course.getSubjectId()); + + // 根据章节的父章节ID,通过章节服务查询并获取对应的父章节实体信息,可能用于在试题列表页面展示章节的层级关系等相关信息(具体根据前端展示需求确定)。 ChapterEntity parentChapter = iChapterService.findById(chapter.getParentId()); - ChapterEntity nextChapter = iChapterService.findNextPoint(chapter.getParentId() , chapter.getOrders()); - + + // 通过章节服务查找给定父章节下,当前章节顺序之后的下一个章节信息,可能用于在试题列表页面提供章节导航等功能(例如查看下一章的试题等情况,具体根据业务逻辑和前端需求确定)。 + ChapterEntity nextChapter = iChapterService.findNextPoint(chapter.getParentId(), chapter.getOrders()); + + // 创建一个用于分页的Page对象,设置当前页码(根据传入的偏移量转换而来,可能需要根据具体分页逻辑进行计算调整)和每页显示的数量。 Page page = new Page<>(); page.setCurrent(offset); page.setSize(limit); - Page questionList = iQuestionService.findByChapterId(chapterId , page); + + // 调用试题服务的findByChapterId方法,根据传入的章节ID和分页对象,获取该章节下符合分页条件的试题列表数据,返回包含试题列表以及分页相关信息的Page对象。 + Page questionList = iQuestionService.findByChapterId(chapterId, page); + + // 将查询到的学科实体信息添加到ModelAndView对象中,以便在视图中展示试题所属学科等相关信息。 model.addObject("subject", subject); + + // 将查询到的课程实体信息添加到ModelAndView对象中,以便在视图中展示试题所属课程等相关信息。 model.addObject("course", course); + + // 将查询到的章节实体信息添加到ModelAndView对象中,以便在视图中展示试题所属章节等相关信息。 model.addObject("chapter", chapter); - model.addObject("parentChapter" , parentChapter); - model.addObject("nextChapter" , nextChapter); + + // 将查询到的父章节实体信息添加到ModelAndView对象中,以便在视图中展示章节的层级关系等相关信息(具体根据前端展示需求确定)。 + model.addObject("parentChapter", parentChapter); + + // 将查询到的下一个章节实体信息添加到ModelAndView对象中,以便在视图中展示章节导航等相关信息(例如查看下一章的试题等情况,具体根据业务逻辑和前端需求确定)。 + model.addObject("nextChapter", nextChapter); + + // 将包含试题列表及分页信息的Page对象添加到ModelAndView对象中,以便在视图中展示具体的试题列表内容。 model.addObject("questionList", questionList); + + // 将课程所属的学科ID添加到ModelAndView对象中,可能用于前端页面的一些交互逻辑或者链接生成等用途(具体根据前端需求确定)。 model.addObject("subjectId", course.getSubjectId()); + + // 将课程的唯一标识符添加到ModelAndView对象中,可能用于前端页面的一些交互逻辑或者链接生成等用途(具体根据前端需求确定)。 model.addObject("courseId", course.getUid()); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户试题列表页面内容。 return model; } catch (Exception e) { + // 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。 model.setViewName("404"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出404页面展示给用户。 return model; } - + } - + /** - * 直接访问题目 - * @param uid - * @param model - * @return + * 处理试题详情页面的GET请求,根据传入的试题唯一标识符(uid),查询并获取与该试题相关的各种信息(如试题本身信息、试题类型描述以及推荐试题列表等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"question",最后返回该ModelAndView对象用于渲染相应的试题详情页面视图给用户。 + * 如果在查询过程中出现异常,则将视图名称设置为"404",返回相应的ModelAndView对象,表示出现错误情况(可能展示404页面给用户)。 + * + * @param uid 试题的唯一标识符,用于定位要展示详情的具体试题。 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中。 + * @return 返回包含视图名称和相关试题及关联数据的ModelAndView对象,用于渲染相应的试题详情页面视图。 */ @RequestMapping(value = {"/question/{uid}.html"}, method = RequestMethod.GET) - public ModelAndView question(@PathVariable String uid , ModelAndView model){ + public ModelAndView question(@PathVariable String uid, ModelAndView model) { try { + // 设置视图名称为"question",对应相应的试题详情页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。 model.setViewName("question"); + + // 根据传入的试题ID,通过试题服务查询并获取对应的试题实体信息,用于在试题详情页面展示试题的详细内容。 QuestionEntity question = iQuestionService.findNormalQuestion(uid); + + // 根据试题实体中存储的试题类型代码,通过QuestionType枚举类的方法获取对应的试题类型描述信息,并设置到试题实体中, + // 用于在试题详情页面展示更直观的试题类型名称(而不是原始的类型代码,提升用户体验)。 question.setQuestionType(QuestionType.getQuestionType(question.getQuestionType()).getDesc()); + + // 将查询到的试题实体信息(包含更新后的试题类型描述)添加到ModelAndView对象中,以便在视图中展示试题的详细内容,如试题题干、选项等信息。 model.addObject("question", question); - - // 推荐试题 - model.addObject("featuredQuestionList", iQuestionService.featuredQuestion(question.getSubjectId(),question.getCourseId())); + + // 获取推荐试题列表,调用试题服务的featuredQuestion方法,传入当前试题的学科ID和课程ID,获取相关的推荐试题列表, + // 并添加到ModelAndView对象中,用于在试题详情页面展示相关的推荐试题内容,方便用户查看其他类似或相关的试题。 + model.addObject("featuredQuestionList", iQuestionService.featuredQuestion(question.getSubjectId(), question.getCourseId())); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户试题详情页面内容。 return model; } catch (Exception e) { + // 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。 model.setViewName("404"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出404页面展示给用户。 return model; } - + } - + + /** + * 处理获取特定试题信息的GET请求,根据传入的试题唯一标识符(uid),调用试题服务的select方法获取对应的试题信息, + * 将获取到的试题信息包装在表示成功的Result对象中返回给前端,方便前端根据统一的格式进行解析和使用试题数据(例如展示试题详情等操作)。 + * + * @param uid 试题的唯一标识符,用于定位要获取信息的具体试题。 + * @param model 用于传递数据到视图的ModelAndView对象(这里在该方法中未实际使用到,可能是为了与其他类似方法保持参数形式一致而添加的)。 + * @return 返回包含指定试题信息的Result对象,若成功获取则Result对象中的数据字段包含相应的试题信息,若出现问题则可能包含相应的错误提示等信息,前端可根据返回结果进行相应展示或处理。 + */ @RequestMapping(value = {"question/getQuestion/{uid}"}, method = RequestMethod.GET) @ResponseBody - public Result getQuestion(@PathVariable String uid , ModelAndView model){ + public Result getQuestion(@PathVariable String uid, ModelAndView model) { return Result.successResult(iQuestionService.select(uid)); } - -} + +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/RegisterController.java b/tamguo/src/main/java/com/tamguo/web/RegisterController.java index a8d9ef6..7f519b8 100644 --- a/tamguo/src/main/java/com/tamguo/web/RegisterController.java +++ b/tamguo/src/main/java/com/tamguo/web/RegisterController.java @@ -20,51 +20,97 @@ import com.tamguo.service.IMemberService; import com.tamguo.util.Result; import com.tamguo.util.ShiroUtils; +// 标识这是一个Spring的控制器类,主要用于处理用户注册相关的Web请求,例如展示注册页面、检查用户名和手机号是否可用以及处理实际的注册提交操作等功能。 @Controller public class RegisterController { - + + // 自动注入IMemberService,用于调用会员相关的业务逻辑方法,比如检查用户名是否已存在、检查手机号是否已注册、执行用户注册操作等,这些操作都依赖于会员服务层提供的具体实现。 @Autowired private IMemberService iMemberService; + /** + * 处理用户注册页面的GET请求,设置视图名称为"register",意味着会查找并渲染名为"register"的视图模板(例如JSP、Thymeleaf等模板文件,具体取决于项目配置)返回给客户端展示注册页面, + * 该页面通常包含用户输入注册信息(如用户名、密码、手机号等)的表单等元素,供用户填写信息进行注册操作。 + * + * @param model 用于传递数据到视图的ModelAndView对象,此处仅设置了视图名称,暂未添加额外数据,用于后续视图渲染展示注册页面。 + * @param session 当前的HttpSession对象,虽然在这里暂时未使用,但在后续注册成功登录等相关操作中可能会用到,用于保存用户相关信息等操作(例如保存登录后的用户信息)。 + * @return 返回包含视图名称的ModelAndView对象,以便Spring的视图解析器根据该名称查找并渲染相应的视图展示给用户。 + */ @RequestMapping(value = "/register", method = RequestMethod.GET) - public ModelAndView register(ModelAndView model , HttpSession session) { + public ModelAndView register(ModelAndView model, HttpSession session) { model.setViewName("register"); return model; - } - + } + + /** + * 处理检查用户名是否可用的GET请求,接收用户名(username)参数,调用会员服务的checkUsername方法进行用户名可用性检查的业务逻辑处理, + * 然后直接将返回的Result对象(包含用户名是否已存在等相关检查结果信息)返回给前端,前端可根据返回的Result对象进行相应的展示或后续处理,例如根据用户名是否可用来决定是否显示某些提示信息或者进行下一步操作等。 + * + * @param username 要检查的用户名,用于在会员服务中查询判断该用户名是否已经被其他用户使用,以确保注册时用户名的唯一性。 + * @return 返回包含用户名检查结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容,前端可根据这些信息进行相应的处理和展示。 + */ @RequestMapping(value = "/checkUsername", method = RequestMethod.GET) @ResponseBody - public Result checkUsername(String username){ + public Result checkUsername(String username) { return iMemberService.checkUsername(username); } - + + /** + * 处理检查手机号是否可用的GET请求,接收手机号(mobile)参数,调用会员服务的checkMobile方法进行手机号可用性检查的业务逻辑处理, + * 然后直接将返回的Result对象(包含手机号是否已注册等相关检查结果信息)返回给前端,前端可根据返回的Result对象进行相应的展示或后续处理,例如根据手机号是否可用来决定是否显示某些提示信息或者进行下一步操作等。 + * + * @param mobile 要检查的手机号,用于在会员服务中查询判断该手机号是否已经被其他用户注册使用,以确保注册时手机号的唯一性(如果业务有此要求)。 + * @return 返回包含手机号检查结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容,前端可根据这些信息进行相应的处理和展示。 + */ @RequestMapping(value = "/checkMobile", method = RequestMethod.GET) @ResponseBody - public Result checkMobile(String mobile){ + public Result checkMobile(String mobile) { return iMemberService.checkMobile(mobile); } - + + /** + * 处理用户提交注册信息的POST请求,通过@RequestBody注解接收前端传来的JSON格式的MemberEntity对象(包含了用户注册时填写的各种信息,如用户名、密码、手机号等)以及HttpSession对象, + * 先调用会员服务的register方法进行用户注册相关的业务逻辑处理,根据返回的Result对象中的状态码(code)来判断注册是否成功, + * 如果注册成功则尝试使用Shiro框架进行登录操作(将注册成功后的用户信息用于登录凭证),并在登录成功后将用户信息保存到HttpSession中;如果注册失败或者登录过程中出现异常,则返回相应的错误提示信息的Result对象给前端。 + * + * @param member 前端传来的包含用户注册信息的MemberEntity对象,通过JSON格式解析后得到,其中包含了注册所需的各种详细信息,如用户名、密码、手机号等,用于在会员服务中进行用户注册操作。 + * @param session 当前的HttpSession对象,用于在注册成功且登录成功后保存当前登录用户的相关信息,方便在后续的请求处理中获取当前用户信息,例如在其他页面展示用户昵称等操作。 + * @return 返回包含注册结果信息的Result对象,若注册成功且登录成功则返回表示成功的Result对象(状态码为200等相关成功信息),若注册失败或者登录出现异常则返回相应的错误提示信息的Result对象(包含不同的状态码和提示内容),前端可根据返回结果进行相应展示或处理。 + */ @RequestMapping(value = "/subRegister", method = RequestMethod.POST) @ResponseBody - public Result subRegister(@RequestBody MemberEntity member , HttpSession session){ + public Result subRegister(@RequestBody MemberEntity member, HttpSession session) { + // 调用会员服务的register方法,传入包含用户注册信息的MemberEntity对象进行用户注册操作,返回包含操作结果信息的Result对象,其中包含状态码、提示信息以及可能的业务数据等内容。 Result result = iMemberService.register(member); - if(result.getCode() == 200) { + + // 判断返回的Result对象中的状态码是否为200,表示用户注册操作成功,通常意味着用户信息已成功保存到数据库等情况符合预期,此时尝试进行登录操作。 + if (result.getCode() == 200) { + // 获取Shiro的Subject对象,它代表了当前执行的用户主体,用于后续进行登录认证等操作。 Subject subject = ShiroUtils.getSubject(); + // 从注册成功返回的Result对象中获取包含注册后的用户信息的MemberEntity对象,用于构建登录凭证(用户名和密码)。 MemberEntity memberEntity = (MemberEntity) result.getResult(); + // 创建一个UsernamePasswordToken对象,将注册后的用户名和用户注册时填写的密码封装进去,作为登录认证的凭证传递给Shiro框架。 UsernamePasswordToken token = new UsernamePasswordToken(memberEntity.getUsername(), member.getPassword()); try { + // 通过Subject对象发起登录认证操作,Shiro框架会根据配置的认证逻辑(如从数据库查询用户信息并比对密码等)进行验证。 subject.login(token); - + + // 如果登录成功,将登录后的用户信息保存到HttpSession中,方便在后续的请求处理中获取当前登录用户的相关信息,键为"currMember"。 session.setAttribute("currMember", ShiroUtils.getMember()); } catch (UnknownAccountException e) { + // 如果Shiro认证过程中抛出UnknownAccountException异常,表示用户名不存在或者未找到对应的用户信息,返回相应的错误提示信息的Result对象给前端。 return Result.result(201, null, "用户名或密码有误,请重新输入或找回密码"); } catch (IncorrectCredentialsException e) { + // 如果Shiro认证过程中抛出IncorrectCredentialsException异常,表示密码错误,返回相应的错误提示信息的Result对象给前端。 return Result.result(202, null, "用户名或密码有误,请重新输入或找回密码"); } catch (LockedAccountException e) { + // 如果Shiro认证过程中抛出LockedAccountException异常,表示账号被锁定,返回相应的错误提示信息的Result对象给前端。 return Result.result(203, null, "账号被锁定"); - } + } } + + // 返回包含注册结果信息的Result对象,若注册成功且登录成功则返回正常的Result对象(包含注册后的用户等相关成功信息),若注册失败或者登录出现异常则返回相应的错误提示信息的Result对象,前端可根据此结果进行相应处理。 return result; } - -} + +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/SubjectController.java b/tamguo/src/main/java/com/tamguo/web/SubjectController.java index a3f723f..afd3172 100644 --- a/tamguo/src/main/java/com/tamguo/web/SubjectController.java +++ b/tamguo/src/main/java/com/tamguo/web/SubjectController.java @@ -26,63 +26,121 @@ import com.tamguo.util.Result; /** * Controller - 考试(高考,建造师,医药师) - * - * @author candy.tam + * 该类作为Spring的控制器,主要用于处理与各类考试相关学科(Subject)主题的Web请求,例如展示特定学科的详细页面、获取课程树结构数据以及获取级联选择器形式的课程树数据等功能, + * 通过调用相应的服务层接口获取所需数据,并根据请求类型将数据以合适的方式返回给前端(渲染视图或者以JSON格式返回数据),同时对可能出现的异常进行了相应处理。 * + * @author candy.tam */ @Controller public class SubjectController { - + + // 创建日志记录器,用于记录在处理各类请求过程中出现的关键信息(如正常的业务日志、异常信息等),方便后续查看日志进行调试、排查问题以及了解系统运行情况。 private Logger logger = LoggerFactory.getLogger(getClass()); - + + // 自动注入IChapterService,用于处理章节相关的业务逻辑,例如根据书籍ID查找课程对应的章节列表等操作,在展示学科相关页面时可能需要获取章节信息进行展示。 @Autowired private IChapterService iChapterService; + + // 自动注入IAreaService,用于处理地区相关的业务逻辑,比如查找根地区列表等操作,可能在学科相关页面展示地区筛选信息或者其他与地区相关的功能中会用到该服务获取的数据。 @Autowired private IAreaService iAreaService; + + // 自动注入ISubjectService,用于处理学科相关的业务逻辑,像根据学科ID查找学科实体、获取课程树结构数据、获取级联选择器形式的课程树数据等操作都是通过该服务来完成,是处理学科相关请求的核心服务依赖。 @Autowired private ISubjectService iSubjectService; + + // 自动注入IBookService,用于处理书籍相关的业务逻辑,例如根据课程ID查询相关书籍列表等操作,在获取学科相关信息时可能会涉及书籍信息的查询,进而基于书籍信息获取其他相关数据(如章节信息等)。 @Autowired private IBookService iBookService; + /** + * 处理展示特定学科详细页面的GET请求,根据传入的学科ID(subjectId),查询并获取与该学科相关的各种信息(如学科本身信息、对应的课程、书籍、章节列表以及地区列表等), + * 将这些信息添加到ModelAndView对象中,设置视图名称为"subject",最后返回该ModelAndView对象用于渲染相应的学科详细页面视图给用户。 + * 如果在查询过程中出现异常,则将异常信息记录到日志中,同时将视图名称设置为"500",返回相应的ModelAndView对象,表示出现服务器内部错误情况(可能展示500页面给用户)。 + * + * @param subjectId 学科的唯一标识符,用于定位要展示详细信息的具体学科。 + * @param model 用于传递数据到视图的ModelAndView对象,在这里将各种相关数据添加到该对象中。 + * @return 返回包含视图名称和相关学科及关联数据的ModelAndView对象,用于渲染相应的学科详细页面视图,若出现异常则返回包含错误视图名称的ModelAndView对象。 + */ @SuppressWarnings("unchecked") @RequestMapping(value = {"subject/{subjectId}.html"}, method = RequestMethod.GET) - public ModelAndView indexAction(@PathVariable String subjectId , ModelAndView model) { + public ModelAndView indexAction(@PathVariable String subjectId, ModelAndView model) { try { + // 根据传入的学科ID,通过学科服务查询并获取对应的学科实体信息,用于在学科详细页面展示学科的基本信息、关联课程等相关内容。 SubjectEntity subject = iSubjectService.find(subjectId); - // 获取第一个科目 + + // 获取该学科下的第一个课程实体信息,这里假设取第一个课程作为某种默认展示或者后续处理的基础(具体业务逻辑可能需根据实际情况调整), + // 比如后续基于该课程查找相关书籍、章节等信息,方便在页面上展示与该学科相关的课程、书籍、章节等内容的关联关系。 CourseEntity course = subject.getCourseList().get(0); - // 获取第一本书 + + // 通过条件查询,查找与当前课程相关的所有书籍列表,可能用于展示该课程下有哪些相关书籍等场景,以便在学科详细页面呈现更丰富的关联信息。 List bookList = iBookService.selectList(Condition.create().eq("course_id", course.getUid())); + + // 获取书籍列表中的第一本图书实体信息(这里同样可能是基于某种默认展示或后续处理的考虑,取第一本作为代表,具体根据业务需求确定), + // 后续可能基于该书籍去查找对应的章节信息等内容,用于在学科详细页面展示课程下书籍包含的章节情况。 BookEntity book = bookList.get(0); - + + // 通过章节服务,查询并获取当前书籍对应的章节列表信息,用于在学科详细页面展示该课程下书籍所包含的章节内容等,方便用户查看学科相关的具体知识章节情况。 List chapterList = iChapterService.findCourseChapter(book.getUid()); - model.setViewName("subject"); - model.addObject("subject", subject); - model.addObject("course" , course); - model.addObject("courseList", subject.getCourseList()); - model.addObject("chapterList" , chapterList); - model.addObject("areaList", iAreaService.findRootArea()); - return model; + + // 设置视图名称为"subject",对应相应的学科详细页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。 + model.setViewName("subject"); + + // 将查询到的学科实体信息添加到ModelAndView对象中,以便在视图中展示学科的详细信息,如学科名称、学科描述等内容。 + model.addObject("subject", subject); + + // 将获取到的第一个课程实体信息添加到ModelAndView对象中,以便在视图中展示学科下的课程相关信息,可能展示课程名称、课程简介等内容(具体根据前端页面需求确定)。 + model.addObject("course", course); + + // 将学科包含的所有课程列表信息添加到ModelAndView对象中,可能用于在页面上展示该学科下所有可选的课程,方便用户切换查看不同课程对应的书籍、章节等信息(具体根据前端展示需求确定)。 + model.addObject("courseList", subject.getCourseList()); + + // 将查询到的章节列表信息添加到ModelAndView对象中,以便在视图中展示课程下书籍所包含的章节内容,方便用户查看具体的知识章节情况。 + model.addObject("chapterList", chapterList); + + // 通过地区服务查找根地区列表信息,可能用于在学科详细页面提供地区筛选等功能(例如按地区查找该学科相关资源等情况,具体根据业务逻辑和前端展示需求确定),并添加到ModelAndView对象中。 + model.addObject("areaList", iAreaService.findRootArea()); + + // 返回包含视图名称和各种相关数据的ModelAndView对象,以便进行视图渲染并展示给用户学科详细页面内容。 + return model; } catch (Exception e) { - logger.error(e.getMessage() , e); + // 如果在查询相关数据过程中出现异常,将异常信息记录到日志中,方便后续查看问题原因、进行调试等操作,记录的信息包括异常消息以及详细的异常堆栈信息。 + logger.error(e.getMessage(), e); + // 将视图名称设置为"500",通常用于表示服务器内部出现错误的情况,意味着出现了未预期的异常导致无法正常处理请求并返回正确的视图内容。 model.setViewName("500"); + // 返回包含错误视图名称的ModelAndView对象,可能会渲染出500页面展示给用户,告知出现了服务器内部错误。 return model; } - - } - + + } + + /** + * 处理获取课程树结构数据的GET请求,调用学科服务的getCourseTree方法获取课程树结构信息(以JSONArray形式返回,具体结构和内容由服务层实现决定,可能是树形结构的课程层级关系数据等), + * 将获取到的数据包装在表示成功的Result对象中返回给前端,方便前端根据统一的格式进行解析和使用课程树数据(例如用于展示课程的层级结构、进行课程选择等操作)。 + * + * @return 返回包含课程树结构数据的Result对象,若成功获取则Result对象中的数据字段包含相应的JSONArray形式的课程树信息,若出现问题则可能包含相应的错误提示等信息,前端可根据返回结果进行相应展示或处理。 + */ @RequestMapping(value = {"subject/getCourseTree.html"}, method = RequestMethod.GET) @ResponseBody - public Result getCourseTree(){ + public Result getCourseTree() { + // 调用学科服务的getCourseTree方法获取课程树结构数据,返回的数据格式为JSONArray,其中包含了课程之间的层级关系等相关信息(具体结构和内容由服务层实现决定)。 JSONArray list = iSubjectService.getCourseTree(); + // 将获取到的课程树结构数据包装在表示成功的Result对象中返回给前端,方便前端按照统一的格式进行处理,Result对象中的数据字段存放实际的课程树信息(这里就是JSONArray类型的list)。 return Result.successResult(list); } - - // [{"value":"11","label":"北京市","children":[{"value":"1101","label":"市辖区"}]}] + + /** + * 处理获取级联选择器形式的课程树数据的GET请求,调用学科服务的getCourseCascaderTree方法获取相应的数据(以JSONArray形式返回,其结构可能符合级联选择器所需的格式,包含节点的value、label以及子节点children等信息), + * 将获取到的数据包装在表示成功的Result对象中返回给前端,方便前端根据统一的格式进行解析和使用该课程树数据(例如用于在前端页面的级联选择器中展示课程层级关系,方便用户进行多级选择等操作)。 + * + * @return 返回包含级联选择器形式课程树数据的Result对象,若成功获取则Result对象中的数据字段包含相应的JSONArray形式的课程树信息,若出现问题则可能包含相应的错误提示等信息,前端可根据返回结果进行相应展示或处理。 + */ @RequestMapping(value = {"subject/getCourseCascaderTree"}, method = RequestMethod.GET) @ResponseBody public Result getCourseCascaderTree() { + // 调用学科服务的getCourseCascaderTree方法获取级联选择器形式的课程树数据,返回的数据格式为JSONArray,其结构符合级联选择器所需的格式(例如示例中展示的包含节点的value、label以及子节点children等信息)。 JSONArray list = iSubjectService.getCourseCascaderTree(); + // 将获取到的级联选择器形式的课程树数据包装在表示成功的Result对象中返回给前端,方便前端按照统一的格式进行处理,Result对象中的数据字段存放实际的课程树信息(这里就是JSONArray类型的list)。 return Result.successResult(list); } -} +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/UEditorController.java b/tamguo/src/main/java/com/tamguo/web/UEditorController.java index 5d0f54d..26dea83 100644 --- a/tamguo/src/main/java/com/tamguo/web/UEditorController.java +++ b/tamguo/src/main/java/com/tamguo/web/UEditorController.java @@ -26,87 +26,168 @@ import com.tamguo.dao.redis.CacheService; import com.tamguo.util.DateUtils; import com.tamguo.util.Setting; +// 标识这是一个Spring的控制器类,主要用于处理与UEditor相关的Web请求,例如返回UEditor的配置信息以及处理图片上传等功能, +// 在图片上传过程中涉及文件的存储操作、根据日期生成文件路径、利用缓存生成唯一文件名编号等逻辑,同时对操作过程中的异常进行了相应处理并返回合适的结果给前端。 @Controller public class UEditorController { - + + // 创建日志记录器,用于记录在处理UEditor相关请求过程中出现的关键信息(如正常的业务日志、文件上传成功或失败信息、异常信息等),方便后续查看日志进行调试、排查问题以及了解系统运行情况。 private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); + + // 通过@Value注解注入配置文件中配置的文件存储路径属性值,该路径用于指定上传文件在服务器端存储的基础目录位置,后续会根据日期等信息进一步构建具体的文件存储子目录。 @Value("${file.storage.path}") private String fileStoragePath; + + // 自动注入Setting对象,该对象可能包含了系统的一些全局设置信息(例如域名等相关配置),在处理文件上传后的文件访问路径等相关逻辑时可能会用到其中的配置数据。 @Autowired private Setting setting; + + // 自动注入CacheService,用于与缓存系统进行交互,在这里主要是利用缓存来生成UEditor上传文件的唯一编号,以保证文件名的唯一性,便于文件管理和区分不同时间上传的文件。 @Autowired private CacheService cacheService; + + // 定义一个表示UEditor文件编号无格式的常量字符串,用于后续格式化生成唯一编号时作为格式模板,这里"00000"表示生成的编号会按照五位数字进行格式化填充(前面补0),具体用途在生成文件名编号逻辑中体现。 private static final String UEDITOR_NO_FORMAT = "00000"; + + // 定义一个UEditor相关的文件名前缀常量字符串,用于构建上传文件的唯一文件名,方便在文件系统中对UEditor上传的文件进行统一标识和区分,与后面生成的编号等组合形成完整的文件名。 private static final String UEDITOR_PREFIX = "UEDITOR"; - - - @RequestMapping(value="/ueditor") - @ResponseBody - public JSONObject ueditor(HttpServletRequest request) { - return JSONObject.parseObject(UEditorConfig.UEDITOR_CONFIG); - } - - @RequestMapping(value="/imgUpload") - @ResponseBody - public Ueditor imgUpload(MultipartFile upfile) throws IOException { - if (!upfile.isEmpty()) { + + /** + * 处理获取UEditor配置信息的请求,直接将预定义的UEditor配置字符串(以JSON格式存储在UEditorConfig.UEDITOR_CONFIG中)解析为JSONObject对象并返回给前端, + * 前端可以根据接收到的配置信息来初始化UEditor编辑器,使其具备相应的功能和展示效果(例如配置支持的文件类型、上传接口地址等相关设置)。 + * + * @param request HttpServletRequest对象,虽然在这里暂时未使用,但在一些复杂的业务场景下可能会根据请求信息进行不同的配置返回或者其他相关处理(例如根据用户权限返回不同的配置等情况),此处仅按固定配置返回。 + * @return 返回解析后的JSONObject对象,包含了UEditor的配置信息,前端可根据该信息进行相应的处理和展示。 + */ + @RequestMapping(value = "/ueditor") + @ResponseBody + public JSONObject ueditor(HttpServletRequest request) { + return JSONObject.parseObject(UEditorConfig.UEDITOR_CONFIG); + } + + /** + * 处理图片上传的请求,接收前端传来的MultipartFile类型的文件(upfile),进行文件保存到服务器指定位置的操作, + * 如果文件上传成功,返回包含成功状态及文件访问URL等信息的Ueditor对象给前端;如果文件为空或者上传过程中出现异常,则返回相应的表示失败状态及错误提示信息的Ueditor对象给前端。 + * + * @param upfile 前端传来的要上传的文件对象,类型为MultipartFile,包含了文件的原始信息(如文件名、文件内容的输入流等),用于后续将文件保存到服务器端的指定位置。 + * @return 返回包含文件上传结果信息的Ueditor对象,若上传成功则对象中包含成功状态("SUCCESS")以及生成的文件访问URL等信息,若上传失败则包含相应的错误状态("ERROR")和错误提示标题(如"上传失败"、"File is empty"等),前端可根据返回结果进行相应展示或处理。 + * @throws IOException 如果在文件流读取、写入等I/O操作过程中出现异常则抛出该异常,例如读取上传文件的输入流或者向服务器文件写入内容时出现问题时会抛出此异常。 + */ + @RequestMapping(value = "/imgUpload") + @ResponseBody + public Ueditor imgUpload(MultipartFile upfile) throws IOException { + // 判断上传的文件是否为空,如果不为空则进行后续的文件保存等操作,为空则直接返回表示错误状态(文件为空)的Ueditor对象给前端。 + if (!upfile.isEmpty()) { InputStream in = null; OutputStream out = null; - + try { + // 根据当前日期(年、月、日)构建文件存储的子目录路径,将其与配置的文件存储基础路径(fileStoragePath)拼接起来,形成完整的文件存储目录路径, + // 这样可以按照日期对上传的文件进行分类存储,便于管理和查找不同时间上传的文件。 String path = fileStoragePath + DateUtils.format(new Date(), "yyyyMMdd"); File dir = new File(path); + // 判断文件存储目录是否存在,如果不存在则创建该目录,确保后续可以将文件保存到正确的目录位置。 if (!dir.exists()) dir.mkdirs(); + + // 调用getUEditorNo方法生成一个唯一的文件名编号,该编号结合文件原始名称的后缀(通过截取原始文件名中最后一个"."之后的部分获取后缀),构建出完整的服务器端存储文件名, + // 以此保证文件名在整个系统中的唯一性,便于文件管理和区分不同的上传文件。 String fileName = this.getUEditorNo() + upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")); File serverFile = new File(dir + File.separator + fileName); + + // 获取上传文件的输入流,用于读取文件内容,后续将通过该输入流把文件内容写入到服务器端的目标文件中。 in = upfile.getInputStream(); + // 创建一个指向服务器端目标文件的输出流,用于将从上传文件读取到的内容写入到该文件中,实现文件保存到服务器的操作。 out = new FileOutputStream(serverFile); + + // 创建一个字节数组缓冲区,用于批量读取和写入文件内容,每次读取1024字节的数据,提高文件读写效率(避免逐个字节读写的低效率情况)。 byte[] b = new byte[1024]; int len = 0; + // 通过循环,不断从输入流中读取数据到字节数组缓冲区(每次最多读取1024字节),直到读取完整个文件内容(即读取的字节数小于等于0表示已读完), + // 然后将缓冲区中的数据写入到输出流对应的服务器端文件中,实现文件内容的复制保存操作。 while ((len = in.read(b)) > 0) { out.write(b, 0, len); } + + // 关闭输出流,释放相关资源,确保文件写入操作完成后正确关闭资源,避免资源泄漏等问题。 out.close(); + // 关闭输入流,释放相关资源,确保文件读取操作完成后正确关闭资源,避免资源泄漏等问题。 in.close(); + + // 将服务器端保存文件的绝对路径信息记录到日志中,方便后续查看文件实际存储位置以及排查文件相关的问题(如文件是否保存成功等情况)。 logger.info("Server File Location=" + serverFile.getAbsolutePath()); - Ueditor ueditor = new Ueditor(); - ueditor.setState("SUCCESS"); - ueditor.setUrl(setting.domain + "files" + "/" +DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName); - return ueditor; + // 创建一个Ueditor对象,用于返回文件上传的结果信息给前端。 + Ueditor ueditor = new Ueditor(); + // 设置文件上传状态为"SUCCESS",表示文件上传成功,前端可以根据该状态进行相应的提示信息展示等处理(例如显示上传成功的提示框)。 + ueditor.setState("SUCCESS"); + // 构建文件的访问URL,将系统配置的域名(通过Setting对象获取)、固定的文件访问路径前缀("files")、按照日期生成的文件存储子目录(通过DateUtils.format生成)以及最终的文件名拼接起来, + // 形成完整的文件访问URL,前端可以使用该URL来访问上传后的文件(例如在编辑器中展示上传的图片等场景)。 + ueditor.setUrl(setting.domain + "files" + "/" + DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName); + + // 返回包含成功状态及文件访问URL等信息的Ueditor对象给前端,告知文件上传成功以及可以通过返回的URL访问该文件。 + return ueditor; } catch (Exception e) { + // 如果在文件上传过程中出现异常(如文件保存失败、流操作异常等情况),创建一个表示错误状态的Ueditor对象,用于返回错误信息给前端。 Ueditor ueditor = new Ueditor(); - ueditor.setState("ERROR"); - ueditor.setTitle("上传失败"); - return ueditor; + // 设置文件上传状态为"ERROR",表示文件上传失败,前端可以根据该状态进行相应的提示信息展示(例如显示上传失败的提示框)。 + ueditor.setState("ERROR"); + // 设置错误提示标题为"上传失败",用于更详细地告知前端用户文件上传出现问题的大致情况,前端可根据此标题进行更具体的错误提示展示(具体展示逻辑由前端决定)。 + ueditor.setTitle("上传失败"); + + // 返回包含错误状态及错误提示标题的Ueditor对象给前端,告知文件上传失败及失败原因(通过标题提示)。 + return ueditor; } finally { - if (out != null) { + // 在finally块中确保输出流资源能够正确关闭,避免因异常等情况导致资源未释放的问题,先判断输出流是否不为空,如果不为空则关闭输出流,并将其置为null,表示资源已释放。 + if (out!= null) { out.close(); out = null; } - if (in != null) { + // 在finally块中确保输入流资源能够正确关闭,避免因异常等情况导致资源未释放的问题,先判断输入流是否不为空,如果不为空则关闭输入流,并将其置为null,表示资源已释放。 + if (in!= null) { in.close(); in = null; } } } else { + // 如果上传的文件为空,创建一个表示错误状态的Ueditor对象,用于返回错误信息给前端。 Ueditor ueditor = new Ueditor(); - ueditor.setState("ERROR"); - ueditor.setTitle("File is empty"); - return ueditor; + // 设置文件上传状态为"ERROR",表示文件上传失败,前端可以根据该状态进行相应的提示信息展示(例如显示上传失败的提示框)。 + ueditor.setState("ERROR"); + // 设置错误提示标题为"File is empty",明确告知前端用户上传的文件为空,前端可根据此标题进行相应的错误提示展示(具体展示逻辑由前端决定)。 + ueditor.setTitle("File is empty"); + + // 返回包含错误状态及错误提示标题的Ueditor对象给前端,告知文件上传失败及失败原因(文件为空)。 + return ueditor; } - } - + } + + /** + * 生成UEditor上传文件的唯一编号,该编号基于当前日期(精确到月)以及缓存中的自增计数来生成,先按照指定格式("yyyyMM")获取当前日期字符串, + * 然后以固定的前缀(UEDITOR_PREFIX)加上日期字符串作为缓存中的键,利用缓存服务(CacheService)对该键对应的值进行自增操作(保证每次生成的编号是顺序递增且唯一的), + * 最后将自增后的值按照固定的格式(UEDITOR_NO_FORMAT,即五位数字,不足五位前面补0)进行格式化,与前缀组合形成完整的唯一文件名编号并返回。 + * + * @return 返回生成的UEditor上传文件的唯一文件名编号,用于构建上传文件在服务器端存储的文件名,确保文件名的唯一性,便于文件管理和区分不同时间上传的文件。 + */ private String getUEditorNo() { + // 创建一个SimpleDateFormat对象,用于按照"yyyyMM"格式对日期进行格式化,即获取当前日期的年和月信息,用于构建与日期相关的唯一编号部分。 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); String format = sdf.format(new Date()); + + // 创建一个DecimalFormat对象,使用定义的UEDITOR_NO_FORMAT常量作为格式化模板,用于将后续生成的自增编号按照五位数字的格式进行格式化(不足五位前面补0),保证编号格式的一致性和唯一性。 DecimalFormat df = new DecimalFormat(UEDITOR_NO_FORMAT); + + // 构建缓存中的键,将固定的UEDITOR_PREFIX前缀与当前日期格式字符串(format)拼接起来,形成一个唯一标识当前月份的UEditor文件编号相关的键,用于在缓存中进行计数操作。 String key = UEDITOR_PREFIX + format; + + // 通过缓存服务(CacheService)对构建的键对应的值进行自增操作,每次调用该方法时,对应键的值会在原来基础上加1,以此生成顺序递增且唯一的编号值,返回自增后的编号值。 Long incr = cacheService.incr(key); + + // 将自增后的编号值按照定义的格式(通过DecimalFormat进行格式化)进行处理,与固定的UEDITOR_PREFIX前缀再次拼接,形成完整的唯一文件名编号,用于后续构建上传文件的文件名,保证文件名的唯一性。 String avatorNo = UEDITOR_PREFIX + df.format(incr); + return avatorNo; } -} +} \ No newline at end of file diff --git a/tamguo/src/main/java/com/tamguo/web/teacher/JoinusController.java b/tamguo/src/main/java/com/tamguo/web/teacher/JoinusController.java index 37ca3ea..23abbf9 100644 --- a/tamguo/src/main/java/com/tamguo/web/teacher/JoinusController.java +++ b/tamguo/src/main/java/com/tamguo/web/teacher/JoinusController.java @@ -15,18 +15,34 @@ import com.tamguo.model.TeacherEntity; import com.tamguo.service.ITeacherService; import com.tamguo.util.Result; +// 标识这是一个Spring的控制器类,用于处理与教师相关的Web请求,并返回相应的视图或数据 @Controller public class JoinusController { - + + // 自动注入ITeacherService,用于处理教师相关的业务逻辑,比如根据手机号获取教师信息、教师注册(加入)等操作 @Autowired private ITeacherService iTeacherService; + /** + * 处理教师注册(加入)页面的GET请求,设置视图名称为"teacher/joinus",用于返回相应的教师注册页面视图给用户,此方法主要是进行视图的初始化设置,暂未涉及更多业务逻辑处理 + * + * @param model 用于传递数据到视图的ModelAndView对象(此处目前未添加额外数据) + * @param session 当前的HttpSession对象,可从中获取会话相关的属性(此处暂时未使用到相关属性) + * @return 返回包含视图名称的ModelAndView对象,以便渲染教师注册页面视图 + */ @RequestMapping(value = "teacher/joinus", method = RequestMethod.GET) - public ModelAndView register(ModelAndView model , HttpSession session) { + public ModelAndView register(ModelAndView model, HttpSession session) { model.setViewName("teacher/joinus"); return model; - } - + } + + /** + * 处理获取教师信息的POST请求,从请求体传入的Map参数中获取手机号(mobile)和验证码(verifyCode)信息, + * 然后调用教师服务根据手机号和验证码获取对应的教师信息,并返回相应的查询结果(通过Result对象包装,可能包含教师信息或者错误提示等情况) + * + * @param param 包含查询教师信息所需参数(手机号和验证码)的Map对象,通过请求体接收 + * @return 返回表示查询教师信息操作结果的Result对象,其中可能包含查找到的教师信息或者表示查询失败等情况的相关提示信息 + */ @RequestMapping(value = "teacher/info", method = RequestMethod.POST) @ResponseBody public Result getTeacher(@RequestBody Map param) { @@ -35,11 +51,18 @@ public class JoinusController { Result result = iTeacherService.getTeacherByMobile(mobile, verifyCode); return result; } - + + /** + * 处理教师注册(加入)的POST请求,接收包含教师相关信息的TeacherEntity对象,调用教师服务的joinus方法进行教师注册(加入)操作, + * 注册成功后返回表示成功的Result对象(此处成功返回的Result对象中未携带额外数据,仅表示操作成功) + * + * @param teacher 包含要注册(加入)的教师相关信息的TeacherEntity对象,通过请求体接收 + * @return 返回表示教师注册(加入)操作结果的Result对象,成功时表示操作成功,若服务层出现异常等情况可能需要进一步处理来返回相应的错误提示信息 + */ @RequestMapping(value = "teacher/joinus", method = RequestMethod.POST) @ResponseBody public Result teacherJoinus(@RequestBody TeacherEntity teacher) { iTeacherService.joinus(teacher); return Result.successResult(null); } -} +} \ No newline at end of file