readme 修改

Signed-off-by: SmileToCandy <smiletocandy@qq.com>
会员中心dcx
Dcx12138 8 months ago
parent 259a2fe6fd
commit da8010bf69

@ -19,38 +19,84 @@ import com.tamguo.service.IChapterService;
import com.tamguo.service.ICourseService; import com.tamguo.service.ICourseService;
import com.tamguo.service.ISubjectService; import com.tamguo.service.ISubjectService;
// 标识这是一个Spring的控制器类用于处理与书籍相关的Web请求并返回相应的视图或数据
@Controller @Controller
public class BookController { public class BookController {
// 自动注入IBookService用于处理书籍相关的业务逻辑比如根据ID查询书籍等操作
@Autowired @Autowired
IBookService iBookService; IBookService iBookService;
// 自动注入IChapterService用于处理章节相关的业务逻辑例如查询某书籍下的章节列表等操作
@Autowired @Autowired
IChapterService iChapterService; IChapterService iChapterService;
// 自动注入ISubjectService用于处理学科相关的业务逻辑像根据学科ID查询学科信息等操作
@Autowired @Autowired
ISubjectService iSubjectService; ISubjectService iSubjectService;
// 自动注入ICourseService用于处理课程相关的业务逻辑例如查询课程信息等操作
@Autowired @Autowired
ICourseService iCourseService; ICourseService iCourseService;
/**
* GETuid
* ModelAndView"book"ModelAndView
* "404"ModelAndView404
*
* @param uid
* @param model ModelAndView
* @return ModelAndView
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@RequestMapping(value = {"book/{uid}"}, method = RequestMethod.GET) @RequestMapping(value = {"book/{uid}"}, method = RequestMethod.GET)
public ModelAndView index(@PathVariable String uid , ModelAndView model) { public ModelAndView index(@PathVariable String uid, ModelAndView model) {
try { try {
// 根据传入的书籍ID通过书籍服务查询并获取对应的书籍实体信息
BookEntity book = iBookService.selectById(uid); BookEntity book = iBookService.selectById(uid);
// 根据书籍所属的学科ID通过学科服务查询并获取对应的学科实体信息
SubjectEntity subject = iSubjectService.find(book.getSubjectId()); SubjectEntity subject = iSubjectService.find(book.getSubjectId());
// 获取该学科下包含的课程列表信息假设SubjectEntity类中有相应的字段存储课程列表这里获取该列表
List<CourseEntity> courseList = subject.getCourseList(); List<CourseEntity> courseList = subject.getCourseList();
// 通过条件查询,查找与当前书籍属于同一课程的其他书籍列表,用于可能在页面展示相关推荐书籍等场景
List<BookEntity> bookList = iBookService.selectList(Condition.create().eq("course_id", book.getCourseId())); List<BookEntity> bookList = iBookService.selectList(Condition.create().eq("course_id", book.getCourseId()));
// 根据书籍所属的课程ID通过课程服务查询并获取对应的课程实体信息
CourseEntity course = iCourseService.selectById(book.getCourseId()); CourseEntity course = iCourseService.selectById(book.getCourseId());
// 通过条件查询,获取当前书籍下的所有章节列表信息,用于在书籍详情页面展示书籍的章节结构等内容
List<ChapterEntity> chapterList = iChapterService.selectList(Condition.create().eq("book_id", uid)); List<ChapterEntity> chapterList = iChapterService.selectList(Condition.create().eq("book_id", uid));
// 将查询到的书籍实体信息添加到ModelAndView对象中以便在视图中可以获取并展示书籍的详细内容
model.addObject("book", book); model.addObject("book", book);
// 将查询到的学科实体信息添加到ModelAndView对象中以便在视图中展示书籍所属学科等相关信息
model.addObject("subject", subject); model.addObject("subject", subject);
// 将查询到的课程实体信息添加到ModelAndView对象中以便在视图中展示书籍所属课程等相关信息
model.addObject("course", course); model.addObject("course", course);
model.addObject("chapterList" , chapterList);
// 将查询到的书籍章节列表信息添加到ModelAndView对象中以便在视图中展示书籍的章节情况
model.addObject("chapterList", chapterList);
// 将查询到的同课程下的其他书籍列表信息添加到ModelAndView对象中以便在视图中展示相关推荐书籍等内容
model.addObject("courseList", courseList); model.addObject("courseList", courseList);
// 将查询到的本课程下的所有书籍列表信息添加到ModelAndView对象中以便在视图中展示相关推荐书籍等内容
model.addObject("bookList", bookList); model.addObject("bookList", bookList);
// 设置视图名称为"book",对应相应的书籍详情页面模板,后续会根据这个名称去查找并渲染对应的视图
model.setViewName("book"); model.setViewName("book");
// 返回包含视图名称和各种相关数据的ModelAndView对象以便进行视图渲染并展示给用户
return model; return model;
} catch (Exception e) { } catch (Exception e) {
// 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况
model.setViewName("404"); model.setViewName("404");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出404页面展示给用户
return model; return model;
} }
} }

@ -10,9 +10,9 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
/** /**
* Controller - * Controller -
* SpringCourseWeb
* *
* @author tamguo * @author tamguo
*
*/ */
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
@ -27,53 +27,111 @@ import com.tamguo.service.ICourseService;
import com.tamguo.service.ISubjectService; import com.tamguo.service.ISubjectService;
import com.tamguo.util.Result; import com.tamguo.util.Result;
// 标识这是一个Spring的控制器类用于处理课程相关的Web请求并返回相应的视图或数据
@Controller @Controller
public class CourseController { public class CourseController {
// 自动注入IChapterService用于处理章节相关的业务逻辑例如查询课程对应的章节信息、获取章节树结构等操作
@Autowired @Autowired
IChapterService iChapterService; IChapterService iChapterService;
// 自动注入ICourseService用于处理课程相关的业务逻辑像根据课程ID查找课程、按学科ID查找课程列表等操作
@Autowired @Autowired
ICourseService iCourseService; ICourseService iCourseService;
// 自动注入ISubjectService用于处理学科相关的业务逻辑例如根据学科ID查找学科信息等操作
@Autowired @Autowired
ISubjectService iSubjectService; ISubjectService iSubjectService;
// 自动注入IBookService用于处理书籍相关的业务逻辑比如根据课程ID查询相关书籍列表等操作
@Autowired @Autowired
IBookService iBookService; IBookService iBookService;
/**
* GETuid
* ModelAndView"chapter"ModelAndView
* "404"ModelAndView404
*
* @param uid
* @param model ModelAndView
* @return ModelAndView
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@RequestMapping(value = {"course/{uid}"}, method = RequestMethod.GET) @RequestMapping(value = {"course/{uid}"}, method = RequestMethod.GET)
public ModelAndView index(@PathVariable String uid , ModelAndView model) { public ModelAndView index(@PathVariable String uid, ModelAndView model) {
try { try {
// 根据传入的课程ID通过课程服务查询并获取对应的课程实体信息
CourseEntity course = iCourseService.find(uid); CourseEntity course = iCourseService.find(uid);
// 通过条件查询,查找与当前课程相关的所有书籍列表,可能用于展示该课程下有哪些相关书籍等场景
List<BookEntity> bookList = iBookService.selectList(Condition.create().eq("course_id", uid)); List<BookEntity> bookList = iBookService.selectList(Condition.create().eq("course_id", uid));
// 获取书籍列表中的第一本图书实体信息(这里假设取第一本作为某种默认展示或后续处理的依据,具体业务逻辑可能需根据实际情况调整)
BookEntity book = bookList.get(0); BookEntity book = bookList.get(0);
// 根据课程所属的学科ID通过学科服务查询并获取对应的学科实体信息
SubjectEntity subject = iSubjectService.find(course.getSubjectId()); SubjectEntity subject = iSubjectService.find(course.getSubjectId());
// 通过章节服务,查询并获取当前课程对应的章节列表信息,用于在课程详情页面展示课程包含的章节内容等
List<ChapterEntity> chapterList = iChapterService.findCourseChapter(book.getUid()); List<ChapterEntity> chapterList = iChapterService.findCourseChapter(book.getUid());
// 通过课程服务,查找与当前课程属于同一学科的其他课程列表,可能用于相关课程推荐等场景
List<CourseEntity> courseList = iCourseService.findBySubjectId(course.getSubjectId()); List<CourseEntity> courseList = iCourseService.findBySubjectId(course.getSubjectId());
// 将查询到的课程章节列表信息添加到ModelAndView对象中以便在视图中展示课程的章节情况
model.addObject("chapterList", chapterList); model.addObject("chapterList", chapterList);
// 将查询到的同学科下的其他课程列表信息添加到ModelAndView对象中以便在视图中展示相关课程推荐等内容
model.addObject("courseList", courseList); model.addObject("courseList", courseList);
// 将查询到的课程实体信息添加到ModelAndView对象中以便在视图中展示课程的详细信息
model.addObject("course", course); model.addObject("course", course);
// 将查询到的学科实体信息添加到ModelAndView对象中以便在视图中展示课程所属学科等相关信息
model.addObject("subject", subject); model.addObject("subject", subject);
// 将查询到的课程相关的书籍列表信息添加到ModelAndView对象中以便在视图中展示课程包含的书籍等内容
model.addObject("bookList", bookList); model.addObject("bookList", bookList);
model.addObject("book" , book);
// 将获取到的首本图书实体信息添加到ModelAndView对象中具体用途根据业务而定
model.addObject("book", book);
// 设置视图名称为"chapter",对应相应的课程详情页面模板,后续会根据这个名称去查找并渲染对应的视图
model.setViewName("chapter"); model.setViewName("chapter");
// 返回包含视图名称和各种相关数据的ModelAndView对象以便进行视图渲染并展示给用户
return model; return model;
} catch (Exception e) { } catch (Exception e) {
// 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况
model.setViewName("404"); model.setViewName("404");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出404页面展示给用户
return model; return model;
} }
} }
/**
* IDGETID
* 便使
*
* @param courseId
* @return List<ChapterEntity>
*/
@RequestMapping(value = {"course/findChapter"}, method = RequestMethod.GET) @RequestMapping(value = {"course/findChapter"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public List<ChapterEntity> findChapterByCourseId(String courseId){ public List<ChapterEntity> findChapterByCourseId(String courseId) {
return iChapterService.findCourseChapter(courseId); return iChapterService.findCourseChapter(courseId);
} }
/**
* IDGETID
* Result便
*
* @param courseId
* @return ResultResult
*/
@RequestMapping(value = {"course/findChapterTreeByCourseId"}, method = RequestMethod.GET) @RequestMapping(value = {"course/findChapterTreeByCourseId"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result findChapterTreeByCourseId(String courseId){ public Result findChapterTreeByCourseId(String courseId) {
return Result.successResult(iChapterService.getChapterTree(courseId)); return Result.successResult(iChapterService.getChapterTree(courseId));
} }

@ -24,72 +24,113 @@ import com.tamguo.util.DateUtils;
/** /**
* *
* Spring
*/ */
@RestController @RestController
public class FileUploadController { public class FileUploadController {
// 创建日志记录器,用于记录文件上传过程中的关键信息,例如文件保存的位置、上传是否成功等情况,方便后续查看日志进行调试和问题排查
private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
// 通过配置文件注入文件存储路径属性值,指定了服务器上用于存放上传文件的基础路径,后续会根据日期等规则在此基础上构建具体的文件存储目录
@Value("${file.storage.path}") @Value("${file.storage.path}")
private String fileStoragePath; private String fileStoragePath;
// 自动注入CacheService用于缓存相关操作在这里主要是借助缓存来生成具有唯一性且按一定规则递增的文件编号文件名的一部分
@Autowired @Autowired
private CacheService cacheService; private CacheService cacheService;
// 定义文件编号的默认格式化字符串,用于格式化生成的文件编号,保证编号格式统一,使其具有固定的长度和格式要求
private static final String FILES_NO_FORMAT = "00000"; private static final String FILES_NO_FORMAT = "00000";
// 定义文件编号的前缀,方便识别文件相关的编号,使其在整体文件名中有一定的标识性,便于区分不同类型或用途的文件
private static final String FILES_PREFIX = "FP"; private static final String FILES_PREFIX = "FP";
/**
* POSTMultipartFileUeditor
* Ueditor
*
* @param upfile MultipartFile
* @return UeditorSUCCESSERROR访
* @throws IOException I/O
*/
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST) @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Ueditor imgUpload(MultipartFile upfile) throws IOException { public Ueditor imgUpload(MultipartFile upfile) throws IOException {
if (!upfile.isEmpty()) { // 判断上传的文件是否为空如果为空则直接返回表示文件为空的错误信息的Ueditor对象给前端
if (!upfile.isEmpty()) {
InputStream in = null; InputStream in = null;
OutputStream out = null; OutputStream out = null;
try { try {
// 根据当前日期构建文件存储的路径将配置的基础存储路径与格式化后的当前日期格式为yyyyMMdd拼接起来方便按日期分类存储文件便于管理和查找
String path = fileStoragePath + DateUtils.format(new Date(), "yyyyMMdd"); String path = fileStoragePath + DateUtils.format(new Date(), "yyyyMMdd");
File dir = new File(path); File dir = new File(path);
// 如果目录不存在,则创建相应的目录,确保文件有存储的位置,避免后续保存文件时因目录不存在而出现错误
if (!dir.exists()) if (!dir.exists())
dir.mkdirs(); dir.mkdirs();
// 生成文件名,结合通过缓存获取的文件编号以及原文件名的后缀组成完整的文件名,保证文件名的唯一性以及符合一定的命名规则
String fileName = this.getTeacherNo() + upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")); String fileName = this.getTeacherNo() + upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf("."));
// 创建表示服务器上要保存的文件的File对象指定其完整的保存路径和文件名
File serverFile = new File(dir + File.separator + fileName); File serverFile = new File(dir + File.separator + fileName);
// 获取文件输入流,用于读取上传文件的内容,以便后续将内容写入到服务器的文件中
in = upfile.getInputStream(); in = upfile.getInputStream();
// 创建文件输出流用于将读取的文件内容写入到服务器指定的存储位置即上面创建的serverFile所代表的文件中
out = new FileOutputStream(serverFile); out = new FileOutputStream(serverFile);
byte[] b = new byte[1024]; byte[] b = new byte[1024];
int len = 0; int len = 0;
// 通过循环读取输入流中的文件内容,并写入到输出流中,实现文件的复制保存操作,将上传的文件从临时存储位置复制到服务器指定的存储位置
while ((len = in.read(b)) > 0) { while ((len = in.read(b)) > 0) {
out.write(b, 0, len); out.write(b, 0, len);
} }
// 关闭输出流,释放相关资源,避免资源泄露
out.close(); out.close();
// 关闭输入流,释放相关资源,避免资源泄露
in.close(); in.close();
// 记录文件在服务器上的存储位置信息到日志中,方便后续查看和排查问题,例如确认文件是否保存成功以及保存的具体位置是否正确等
logger.info("Server File Location=" + serverFile.getAbsolutePath()); logger.info("Server File Location=" + serverFile.getAbsolutePath());
Ueditor ueditor = new Ueditor(); // 创建表示文件上传成功的Ueditor对象并设置相应的成功状态、原文件名作为标题以及文件在服务器上的访问路径等信息
ueditor.setState("SUCCESS"); Ueditor ueditor = new Ueditor();
ueditor.setTitle(upfile.getOriginalFilename()); ueditor.setState("SUCCESS");
ueditor.setUrl("files" + "/" +DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName); ueditor.setTitle(upfile.getOriginalFilename());
return ueditor; ueditor.setUrl("files" + "/" + DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName);
return ueditor;
} catch (Exception e) { } catch (Exception e) {
// 如果在文件上传过程中出现异常创建表示文件上传失败的Ueditor对象并设置相应的错误状态和提示信息这里统一设置为"上传失败"),然后返回该对象告知前端上传失败
Ueditor ueditor = new Ueditor(); Ueditor ueditor = new Ueditor();
ueditor.setState("ERROR"); ueditor.setState("ERROR");
ueditor.setTitle("上传失败"); ueditor.setTitle("上传失败");
return ueditor; return ueditor;
} finally { } finally {
if (out != null) { // 在最终块中确保输出流资源被正确关闭,避免资源泄露,即使在前面出现异常的情况下也能保证资源的正确释放
if (out!= null) {
out.close(); out.close();
out = null; out = null;
} }
if (in != null) { // 在最终块中确保输入流资源被正确关闭,避免资源泄露,即使在前面出现异常的情况下也能保证资源的正确释放
if (in!= null) {
in.close(); in.close();
in = null; in = null;
} }
} }
} else { } else {
// 如果上传的文件为空创建表示文件为空的错误的Ueditor对象并设置相应的错误状态和提示信息然后返回该对象告知前端文件为空
Ueditor ueditor = new Ueditor(); Ueditor ueditor = new Ueditor();
ueditor.setState("ERROR"); ueditor.setState("ERROR");
ueditor.setTitle("File is empty"); ueditor.setTitle("File is empty");
return ueditor; return ueditor;
} }
} }
/**
*
* 便
*
* @return
*/
private String getTeacherNo() { private String getTeacherNo() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
String format = sdf.format(new Date()); String format = sdf.format(new Date());

@ -5,36 +5,71 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
// 标识这是一个Spring的控制器类用于处理不同路径的Web请求并返回相应的视图给客户端展示不同的页面内容。
@Controller @Controller
public class IndexController { public class IndexController {
@RequestMapping(value = "/", method = RequestMethod.GET) /**
* "/"GET"index""index"JSPThymeleaf
*
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView indexAction(ModelAndView model) { public ModelAndView indexAction(ModelAndView model) {
model.setViewName("index"); model.setViewName("index");
return model; return model;
} }
/**
* "/index"GET"index"访使
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/index", method = RequestMethod.GET) @RequestMapping(value = "/index", method = RequestMethod.GET)
public ModelAndView mainAction(ModelAndView model) { public ModelAndView mainAction(ModelAndView model) {
model.setViewName("index"); model.setViewName("index");
return model; return model;
} }
/**
* "/baidu_verify_5agfTbCO3Q"GET"thirdparty/baidu_verify_5agfTbCO3Q"
*
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/baidu_verify_5agfTbCO3Q", method = RequestMethod.GET) @RequestMapping(value = "/baidu_verify_5agfTbCO3Q", method = RequestMethod.GET)
public ModelAndView baidu_verify_5agfTbCO3Q(ModelAndView model) { public ModelAndView baidu_verify_5agfTbCO3Q(ModelAndView model) {
model.setViewName("thirdparty/baidu_verify_5agfTbCO3Q"); model.setViewName("thirdparty/baidu_verify_5agfTbCO3Q");
return model; return model;
} }
/**
* "/baidu_verify_iAm7387J0l"GET"thirdparty/baidu_verify_iAm7387J0l"
*
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/baidu_verify_iAm7387J0l", method = RequestMethod.GET) @RequestMapping(value = "/baidu_verify_iAm7387J0l", method = RequestMethod.GET)
public ModelAndView baidu_verify_iAm7387J0l(ModelAndView model) { public ModelAndView baidu_verify_iAm7387J0l(ModelAndView model) {
model.setViewName("thirdparty/baidu_verify_iAm7387J0l"); model.setViewName("thirdparty/baidu_verify_iAm7387J0l");
return model; return model;
} }
/**
* "/sogousiteverification"GET"thirdparty/sogousiteverification"
*
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/sogousiteverification", method = RequestMethod.GET) @RequestMapping(value = "/sogousiteverification", method = RequestMethod.GET)
public ModelAndView sogousiteverification(ModelAndView model) { public ModelAndView sogousiteverification(ModelAndView model) {
model.setViewName("thirdparty/sogousiteverification"); model.setViewName("thirdparty/sogousiteverification");
return model; return model;
} }
} }

@ -27,94 +27,176 @@ import com.google.code.kaptcha.Producer;
import com.tamguo.util.Result; import com.tamguo.util.Result;
import com.tamguo.util.ShiroUtils; import com.tamguo.util.ShiroUtils;
// 标识这是一个Spring的控制器类主要用于处理用户登录相关的Web请求包括生成验证码、展示登录页面以及处理登录提交等操作。
@Controller @Controller
public class LoginController { public class LoginController {
// 自动注入Producer用于生成验证码相关的操作比如创建验证码文本和对应的图片验证码。
@Autowired @Autowired
private Producer producer; private Producer producer;
/**
* "captcha.jpg"
* JPEG
* Shiro便
*
* @param response HttpServletResponse便
* @throws ServletException Servlet
* @throws IOException I/O
*/
@RequestMapping("captcha.jpg") @RequestMapping("captcha.jpg")
public void captcha(HttpServletResponse response) throws ServletException, IOException { public void captcha(HttpServletResponse response) throws ServletException, IOException {
// 设置响应头,禁止客户端缓存验证码图片,确保每次获取的验证码都是新生成的。
response.setHeader("Cache-Control", "no-store, no-cache"); response.setHeader("Cache-Control", "no-store, no-cache");
// 设置响应的内容类型为JPEG格式的图片告知客户端返回的数据是图片类型以便正确解析和显示。
response.setContentType("image/jpeg"); response.setContentType("image/jpeg");
// 生成文字验证码
// 生成验证码的文本内容通常是由数字、字母等组成的随机字符串具体生成规则由所使用的验证码生成组件这里是Producer决定。
String text = producer.createText(); String text = producer.createText();
// 生成图片验证码 // 根据生成的验证码文本创建对应的图片验证码生成的是一个BufferedImage类型的图片对象包含了验证码文本的可视化表示形式。
BufferedImage image = producer.createImage(text); BufferedImage image = producer.createImage(text);
// 保存到shiro session
// 将生成的验证码文本保存到Shiro的会话中以Constants.KAPTCHA_SESSION_KEY作为键方便后续在验证用户输入的验证码时从会话中获取并比对。
ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text); ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);
// 获取ServletResponse的输出流用于将生成的图片数据写入到响应中发送给客户端进行显示。
ServletOutputStream out = response.getOutputStream(); ServletOutputStream out = response.getOutputStream();
// 使用ImageIO将BufferedImage格式的图片以JPEG格式写入到输出流中实现将验证码图片返回给客户端的功能。
ImageIO.write(image, "jpg", out); ImageIO.write(image, "jpg", out);
} }
/**
* GET"login""login"JSPThymeleaf
* "isVerifyCode""0"
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/login", method = RequestMethod.GET) @RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(ModelAndView model){ public ModelAndView login(ModelAndView model) {
model.setViewName("login"); model.setViewName("login");
model.addObject("isVerifyCode" , "0"); model.addObject("isVerifyCode", "0");
return model; return model;
} }
/**
* POSTShiro
*
*
* @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) @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); Result result = Result.successResult(null);
if(StringUtils.isEmpty(verifyCode)) {
// 判断用户输入的验证码是否为空如果为空则表示用户未输入验证码设置相应的错误提示信息到Result对象中。
if (StringUtils.isEmpty(verifyCode)) {
result = Result.result(202, null, "请输入验证码"); result = Result.result(202, null, "请输入验证码");
} else if(StringUtils.isNotEmpty(verifyCode)){ } else if (StringUtils.isNotEmpty(verifyCode)) {
// 如果用户输入了验证码从Shiro会话中获取之前生成并保存的验证码文本用于和用户输入的验证码进行比对验证。
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY); String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
// 忽略大小写比较用户输入的验证码和会话中的验证码是否一致如果不一致则表示验证码错误设置相应的错误提示信息到Result对象中。
if (!verifyCode.equalsIgnoreCase(kaptcha)) { if (!verifyCode.equalsIgnoreCase(kaptcha)) {
result = Result.result(205, null, "验证码错误"); result = Result.result(205, null, "验证码错误");
} else { } else {
// 如果验证码验证通过获取Shiro的Subject对象它代表了当前执行的用户主体用于后续进行登录认证等操作。
Subject subject = ShiroUtils.getSubject(); Subject subject = ShiroUtils.getSubject();
// 创建一个UsernamePasswordToken对象将用户输入的用户名和密码封装进去作为登录认证的凭证传递给Shiro框架。
UsernamePasswordToken token = new UsernamePasswordToken(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try { try {
// 通过Subject对象发起登录认证操作Shiro框架会根据配置的认证逻辑如从数据库查询用户信息并比对密码等进行验证。
subject.login(token); subject.login(token);
// 如果登录成功将登录后的用户信息保存到HttpSession中方便在后续的请求处理中获取当前登录用户的相关信息键为"currMember"。
session.setAttribute("currMember", ShiroUtils.getMember()); session.setAttribute("currMember", ShiroUtils.getMember());
// 重定向到登录成功后的页面(这里是"member/index.html",可能是会员相关的首页之类的页面,具体根据业务需求确定)。
response.sendRedirect("member/index.html"); response.sendRedirect("member/index.html");
// 登录成功后直接返回null因为已经进行了重定向操作不需要再返回视图相关的内容了。
return null; return null;
} catch (UnknownAccountException e) { } catch (UnknownAccountException e) {
// 如果Shiro认证过程中抛出UnknownAccountException异常表示用户名不存在或者未找到对应的用户信息设置相应的错误提示信息到Result对象中。
result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码"); result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
} catch (IncorrectCredentialsException e) { } catch (IncorrectCredentialsException e) {
// 如果Shiro认证过程中抛出IncorrectCredentialsException异常表示密码错误设置相应的错误提示信息到Result对象中。
result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码"); result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
} catch (LockedAccountException e) { } catch (LockedAccountException e) {
// 如果Shiro认证过程中抛出LockedAccountException异常表示账号被锁定设置相应的错误提示信息到Result对象中。
result = Result.result(203, null, "账号被锁定"); result = Result.result(203, null, "账号被锁定");
} }
} }
} }
// 如果登录验证未通过(出现各种错误情况),设置视图名称为"login",表示返回登录页面展示给用户相应的错误提示信息。
model.setViewName("login"); model.setViewName("login");
// 将登录结果的状态码添加到视图模型中,方便前端页面根据状态码进行不同的提示信息展示等逻辑处理。
model.addObject("code", result.getCode()); model.addObject("code", result.getCode());
model.addObject("msg" , result.getMessage()); // 将登录结果的提示信息添加到视图模型中,以便在登录页面展示给用户具体的错误原因等内容。
model.addObject("msg", result.getMessage());
// 将用户输入的用户名添加到视图模型中,可能用于前端页面保留用户之前输入的用户名,提升用户体验等用途(具体根据前端需求确定)。
model.addObject("username", username); model.addObject("username", username);
return model; return model;
} }
/**
* GET
* Result
* submitLoginShiroResponseBodyResult
*
* @param username
* @param password
* @param captcha
* @param model ModelAndView使
* @param session HttpSession
* @return Result
*/
@RequestMapping(value = "/miniLogin", method = RequestMethod.GET) @RequestMapping(value = "/miniLogin", method = RequestMethod.GET)
@ResponseBody @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; Result result = null;
if(StringUtils.isEmpty(captcha)) { // 判断用户输入的验证码是否为空如果为空则表示用户未输入验证码设置相应的错误提示信息到Result对象中。
if (StringUtils.isEmpty(captcha)) {
result = Result.result(204, null, "请输入验证码"); result = Result.result(204, null, "请输入验证码");
} else if(StringUtils.isNotEmpty(captcha)){ } else if (StringUtils.isNotEmpty(captcha)) {
// 如果用户输入了验证码从Shiro会话中获取之前生成并保存的验证码文本用于和用户输入的验证码进行比对验证。
String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY); String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY);
// 忽略大小写比较用户输入的验证码和会话中的验证码是否一致如果不一致则表示验证码错误设置相应的错误提示信息到Result对象中。
if (!captcha.equalsIgnoreCase(kaptcha)) { if (!captcha.equalsIgnoreCase(kaptcha)) {
result = Result.result(205, null, "验证码错误"); result = Result.result(205, null, "验证码错误");
}else { } else {
// 如果验证码验证通过获取Shiro的Subject对象它代表了当前执行的用户主体用于后续进行登录认证等操作。
Subject subject = ShiroUtils.getSubject(); Subject subject = ShiroUtils.getSubject();
// 创建一个UsernamePasswordToken对象将用户输入的用户名和密码封装进去作为登录认证的凭证传递给Shiro框架。
UsernamePasswordToken token = new UsernamePasswordToken(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try { try {
// 通过Subject对象发起登录认证操作Shiro框架会根据配置的认证逻辑如从数据库查询用户信息并比对密码等进行验证。
subject.login(token); subject.login(token);
// 如果登录成功将登录后的用户信息保存到HttpSession中方便在后续的请求处理中获取当前登录用户的相关信息键为"currMember"。
session.setAttribute("currMember", ShiroUtils.getMember()); session.setAttribute("currMember", ShiroUtils.getMember());
// 创建表示登录成功的Result对象并将登录后的用户信息设置到Result对象中以便返回给客户端。
result = Result.successResult(ShiroUtils.getMember()); result = Result.successResult(ShiroUtils.getMember());
} catch (UnknownAccountException e) { } catch (UnknownAccountException e) {
// 如果Shiro认证过程中抛出UnknownAccountException异常表示用户名不存在或者未找到对应的用户信息设置相应的错误提示信息到Result对象中。
result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码"); result = Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
} catch (IncorrectCredentialsException e) { } catch (IncorrectCredentialsException e) {
// 如果Shiro认证过程中抛出IncorrectCredentialsException异常表示密码错误设置相应的错误提示信息到Result对象中。
result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码"); result = Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
} catch (LockedAccountException e) { } catch (LockedAccountException e) {
// 如果Shiro认证过程中抛出LockedAccountException异常表示账号被锁定设置相应的错误提示信息到Result对象中。
result = Result.result(203, null, "账号被锁定"); result = Result.result(203, null, "账号被锁定");
} }
} }
} }
return result; return result;
} }
} }

@ -25,84 +25,191 @@ import com.tamguo.util.TamguoConstant;
/** /**
* Controller - * Controller -
* SpringWeb
* ModelAndViewJSON@ResponseBody
* *
* @author candy.tam * @author candy.tam
*
*/ */
@Controller @Controller
public class PaperController { public class PaperController {
// 自动注入ICourseService用于处理课程相关的业务逻辑比如根据课程ID查找课程、按学科ID查找课程列表等操作在获取试卷相关信息时可能会涉及课程信息的查询。
@Autowired @Autowired
private ICourseService iCourseService; private ICourseService iCourseService;
// 自动注入IAreaService用于处理地区相关的业务逻辑例如查找根地区列表等操作可能在按地区筛选试卷等功能中会用到地区相关信息的查询。
@Autowired @Autowired
private IAreaService iAreaService; private IAreaService iAreaService;
// 自动注入IPaperService用于处理试卷相关的业务逻辑像查找试卷、获取试卷列表、根据各种条件筛选试卷、获取推荐试卷等操作都是通过该服务来完成。
@Autowired @Autowired
private IPaperService iPaperService; private IPaperService iPaperService;
// 自动注入IQuestionService用于处理试题相关的业务逻辑例如查找试卷对应的试题列表等操作在试卷详情页面展示试题信息时会调用该服务。
@Autowired @Autowired
private IQuestionService iQuestionService; private IQuestionService iQuestionService;
// 自动注入ISubjectService用于处理学科相关的业务逻辑例如根据学科ID查找学科信息等操作试卷通常与特定学科相关查询试卷相关信息时可能需要获取学科相关内容。
@Autowired @Autowired
private ISubjectService iSubjectService; private ISubjectService iSubjectService;
/**
* GETIDID
* ModelAndView"paperlist"ModelAndView
* "404"ModelAndView404
*
* @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) @RequestMapping(value = {"paperlist/{subjectId}-{courseId}-{paperType}-{year}-{area}-{pageNum}"}, method = RequestMethod.GET)
public ModelAndView indexAction(@PathVariable String subjectId , @PathVariable String courseId , @PathVariable String paperType, public ModelAndView indexAction(@PathVariable String subjectId, @PathVariable String courseId,
@PathVariable String year , @PathVariable String area , @PathVariable Integer pageNum, ModelAndView model) { @PathVariable String paperType, @PathVariable String year, @PathVariable String area,
try { @PathVariable Integer pageNum, ModelAndView model) {
model.setViewName("paperlist"); try {
// 设置视图名称为"paperlist",对应相应的试卷列表页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。
CourseEntity course = iCourseService.find(courseId); model.setViewName("paperlist");
List<CourseEntity> courseList = iCourseService.findBySubjectId(subjectId);
SubjectEntity subject = iSubjectService.find(subjectId); // 根据传入的课程ID通过课程服务查询并获取对应的课程实体信息用于在试卷列表页面展示试卷所属课程等相关信息。
List<AreaEntity> areaList = iAreaService.findRootArea(); CourseEntity course = iCourseService.find(courseId);
PageUtils page = PageUtils.getPage(iPaperService.findList(subjectId , courseId , paperType , year , area , pageNum));
if(course == null) { // 通过课程服务查找与传入学科ID对应的所有课程列表可能用于在试卷列表页面展示该学科下的所有课程方便用户切换查看不同课程的试卷情况。
course = courseList.get(0); List<CourseEntity> courseList = iCourseService.findBySubjectId(subjectId);
}
Long total = iPaperService.getPaperTotal(); // 根据传入的学科ID通过学科服务查询并获取对应的学科实体信息用于在试卷列表页面展示试卷所属学科等相关信息。
model.addObject("courseList", courseList); SubjectEntity subject = iSubjectService.find(subjectId);
model.addObject("subject", subject);
model.addObject("course", course); // 通过地区服务查找根地区列表信息,可能用于在试卷列表页面提供地区筛选的下拉菜单等功能,展示所有可选的地区范围(具体根据业务需求而定)。
model.addObject("areaList", areaList); List<AreaEntity> areaList = iAreaService.findRootArea();
model.addObject("paperPage" , page);
model.addObject("total" , total); // 调用试卷服务的findList方法根据传入的多个条件学科ID、课程ID、试卷类型、年份、地区、页码获取相应的试卷列表数据并通过PageUtils工具类进行分页相关的处理得到包含分页信息的PageUtils对象。
model.addObject("courseId", course.getUid()); PageUtils page = PageUtils.getPage(iPaperService.findList(subjectId, courseId, paperType, year, area, pageNum));
model.addObject("paperType", paperType);
model.addObject("year", year); // 如果通过课程ID未查询到对应的课程实体可能课程ID不存在或者其他原因导致查询失败则取课程列表中的第一个课程作为默认展示具体根据业务逻辑需求调整
model.addObject("area", area); if (course == null) {
return model; 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) { } catch (Exception e) {
// 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。
model.setViewName("404"); model.setViewName("404");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出404页面展示给用户。
return model; return model;
} }
} }
/**
* GETID
* ModelAndView"paper"ModelAndView
* "404"ModelAndView404
*
* @param paperId
* @param model ModelAndView
* @return ModelAndView
*/
@RequestMapping(value = {"/paper/{paperId}.html"}, method = RequestMethod.GET) @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 { try {
// 设置视图名称为"paper",对应相应的试卷详情页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。
model.setViewName("paper"); model.setViewName("paper");
// 根据传入的试卷ID通过试卷服务查询并获取对应的试卷实体信息用于在试卷详情页面展示试卷的详细内容。
PaperEntity paper = iPaperService.find(paperId); PaperEntity paper = iPaperService.find(paperId);
// 将查询到的试卷实体信息添加到ModelAndView对象中以便在视图中展示试卷的详细内容如试卷名称、考试时间等信息。
model.addObject("paper", paper); 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)); model.addObject("questionList", iQuestionService.findPaperQuestion(paperId));
// 获取推荐试卷 // 获取真题推荐试卷列表调用试卷服务的featuredPaper方法传入特定的真题标识TamguoConstant.ZHENGTI_PAPER_ID和当前试卷的学科ID获取相关的真题推荐试卷列表
// 并添加到ModelAndView对象中用于在试卷详情页面展示相关的推荐试卷内容方便用户查看其他类似的真题试卷。
model.addObject("zhentiPaperList", iPaperService.featuredPaper(TamguoConstant.ZHENGTI_PAPER_ID, paper.getSubjectId())); 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())); 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())); model.addObject("yatiPaperList", iPaperService.featuredPaper(TamguoConstant.YATI_PAPER_ID, paper.getSubjectId()));
// 获取热门试卷列表调用试卷服务的findHotPaper方法传入当前试卷的学科ID和课程ID获取相关的热门试卷列表
// 并添加到ModelAndView对象中用于在试卷详情页面展示相关的推荐试卷内容方便用户查看其他热门的试卷。
model.addObject("hotPaperList", iPaperService.findHotPaper(paper.getSubjectId(), paper.getCourseId())); model.addObject("hotPaperList", iPaperService.findHotPaper(paper.getSubjectId(), paper.getCourseId()));
// 返回包含视图名称和各种相关数据的ModelAndView对象以便进行视图渲染并展示给用户试卷详情页面内容。
return model; return model;
} catch (Exception e) { } catch (Exception e) {
// 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。
model.setViewName("404"); model.setViewName("404");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出404页面展示给用户。
return model; return model;
} }
} }
/**
* IDGETIDJSON
* 便
*
* @param areaId
* @param type
* @return List<PaperEntity>
*/
@RequestMapping(value = {"/paper/area/{areaId}-{type}.html"}, method = RequestMethod.GET) @RequestMapping(value = {"/paper/area/{areaId}-{type}.html"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public List<PaperEntity> findPaperByAreaId(@PathVariable String areaId ,@PathVariable String type){ public List<PaperEntity> findPaperByAreaId(@PathVariable String areaId, @PathVariable String type) {
return iPaperService.findPaperByAreaId(areaId , type); return iPaperService.findPaperByAreaId(areaId, type);
} }
} }

@ -10,65 +10,146 @@ import org.springframework.web.servlet.ModelAndView;
import com.tamguo.service.IMemberService; import com.tamguo.service.IMemberService;
import com.tamguo.util.Result; import com.tamguo.util.Result;
// 标识这是一个Spring的控制器类主要用于处理与用户密码相关的各种操作的Web请求例如确认账号、安全验证、重置密码以及检查账号是否存在等功能。
@Controller @Controller
public class PasswordController { public class PasswordController {
// 自动注入IMemberService用于调用会员相关的业务逻辑方法比如确认账号、进行安全检查、重置密码以及检查账号有效性等操作这些操作都依赖于会员服务层提供的具体实现。
@Autowired @Autowired
private IMemberService iMemberService; private IMemberService iMemberService;
/**
* GET"password/confirmAccount""password/confirmAccount"JSPThymeleaf
*
*
* @param model ModelAndView
* @return ModelAndView便Spring
*/
@RequestMapping(value = "password/find", method = RequestMethod.GET) @RequestMapping(value = "password/find", method = RequestMethod.GET)
public ModelAndView confirmAccount(ModelAndView model){ public ModelAndView confirmAccount(ModelAndView model) {
model.setViewName("password/confirmAccount"); model.setViewName("password/confirmAccount");
return model; return model;
} }
/**
* POSTusernameveritycodeconfirmAccount
* Resultcode
*
* @param username
* @param veritycode
* @param model ModelAndView便
* @return ModelAndView便Spring
*/
@RequestMapping(value = "password/confirmAccount", method = RequestMethod.POST) @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); Result result = iMemberService.confirmAccount(username, veritycode);
if(result.getCode() == 200){
// 判断返回的Result对象中的状态码是否为200表示账号确认操作成功通常意味着账号存在且验证码匹配等情况符合预期。
if (result.getCode() == 200) {
// 如果账号确认成功,设置视图名称为"password/securityCheck",表示要跳转到密码找回流程中的安全检查页面,用于后续进一步验证用户身份等操作。
model.setViewName("password/securityCheck"); model.setViewName("password/securityCheck");
// 将确认账号操作返回的Result对象添加到视图模型中可能在安全检查页面会展示一些相关的提示信息或者使用其中的数据具体根据前端页面需求确定
model.addObject("result", result); model.addObject("result", result);
model.addObject("isEmail", username.contains("@") ? "1" : "0"); // 根据用户名中是否包含"@"符号来判断是邮箱账号还是手机号等其他形式账号,将判断结果("1"表示邮箱账号,"0"表示非邮箱账号)添加到视图模型中,
}else{ // 可能用于安全检查页面根据账号类型进行不同的验证方式展示等逻辑处理(例如邮箱账号可能通过邮件验证,手机号账号可能通过短信验证等,具体根据业务逻辑确定)。
model.addObject("isEmail", username.contains("@")? "1" : "0");
} else {
// 如果账号确认失败,设置视图名称为"password/confirmAccount",表示返回确认账号页面,以便用户重新输入正确的信息进行账号确认操作。
model.setViewName("password/confirmAccount"); model.setViewName("password/confirmAccount");
// 将用户输入的账号信息添加到视图模型中,可能用于前端页面保留用户之前输入的账号内容,方便用户查看和修改,提升用户体验。
model.addObject("account", username); model.addObject("account", username);
model.addObject("username",username); // 将用户输入的用户名添加到视图模型中,可能同样用于前端页面保留用户名信息,具体根据前端页面展示需求确定。
model.addObject("username", username);
// 将用户输入的验证码添加到视图模型中,可能用于前端页面展示用户之前输入的验证码内容,方便用户查看是否输入有误等情况。
model.addObject("veritycode", veritycode); model.addObject("veritycode", veritycode);
// 将操作失败返回的Result对象中的状态码添加到视图模型中方便前端页面根据状态码进行不同的错误提示信息展示等逻辑处理告知用户具体是哪种验证失败的情况。
model.addObject("code", result.getCode()); model.addObject("code", result.getCode());
} }
// 返回包含视图名称和相应数据的ModelAndView对象以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户。
return model; return model;
} }
/**
* POSTusernameisEmailmobileVcodesecurityCheck
* Resultcode
*
* @param username
* @param isEmail "1""0"
* @param mobileVcode 使
* @param model ModelAndView便
* @return ModelAndView便Spring
*/
@RequestMapping(value = "password/securityCheck", method = RequestMethod.POST) @RequestMapping(value = "password/securityCheck", method = RequestMethod.POST)
public ModelAndView securityCheck(String username , String isEmail , String mobileVcode , ModelAndView model){ public ModelAndView securityCheck(String username, String isEmail, String mobileVcode, ModelAndView model) {
Result result = iMemberService.securityCheck(username , isEmail , mobileVcode); // 调用会员服务的securityCheck方法传入用户名、是否为邮箱账号标识以及手机验证码等参数进行安全检查操作返回包含操作结果信息的Result对象其中包含状态码、提示信息以及可能的业务数据等内容。
if(result.getCode() == 200){ Result result = iMemberService.securityCheck(username, isEmail, mobileVcode);
// 判断返回的Result对象中的状态码是否为200表示安全检查操作成功通常意味着用户身份验证通过等情况符合预期可以进行下一步的密码重置操作。
if (result.getCode() == 200) {
// 将用户名添加到视图模型中,可能在重置密码页面会展示用户名等相关信息,告知用户当前正在重置哪个账号的密码(具体根据前端页面需求确定)。
model.addObject("username", username); model.addObject("username", username);
model.addObject("resetPasswordKey" , result.getResult()); // 将安全检查操作成功后返回的Result对象中包含的用于重置密码的关键信息例如重置密码的令牌等具体根据业务逻辑确定添加到视图模型中
// 后续在重置密码页面会使用该信息来确保是经过安全验证后的合法操作,用于关联和验证密码重置请求。
model.addObject("resetPasswordKey", result.getResult());
// 设置视图名称为"password/resetPassword",表示要跳转到密码找回流程中的重置密码页面,用于用户输入新的密码等操作。
model.setViewName("password/resetPassword"); model.setViewName("password/resetPassword");
}else{ } else {
// 如果安全检查失败将安全检查操作返回的Result对象添加到视图模型中可能在安全检查页面会展示一些相关的错误提示信息或者使用其中的数据具体根据前端页面需求确定
model.addObject("result", result); model.addObject("result", result);
// 将是否为邮箱账号的标识添加到视图模型中,可能用于安全检查页面根据账号类型进行不同的错误提示信息展示等逻辑处理,告知用户具体是哪种账号类型的验证失败情况。
model.addObject("isEmail", isEmail); model.addObject("isEmail", isEmail);
// 添加一个表示验证码错误的标识(值为"1")到视图模型中,方便前端页面根据该标识进行相应的错误提示信息展示,告知用户验证码输入有误等情况(具体根据前端页面展示逻辑确定)。
model.addObject("codeError", "1"); model.addObject("codeError", "1");
// 设置视图名称为"password/securityCheck",表示返回安全检查页面,以便用户重新输入正确的信息进行安全检查操作。
model.setViewName("password/securityCheck"); model.setViewName("password/securityCheck");
} }
// 返回包含视图名称和相应数据的ModelAndView对象以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户。
return model; return model;
} }
/**
* POSTresetPasswordKeyusernamepasswordverifypwd
* resetPasswordResultcode
*
* @param resetPasswordKey
* @param username
* @param password
* @param verifypwd
* @param model ModelAndView便Spring
* @return ModelAndView便Spring
*/
@RequestMapping(value = "password/resetPassword", method = RequestMethod.POST) @RequestMapping(value = "password/resetPassword", method = RequestMethod.POST)
public ModelAndView resetPassword(String resetPasswordKey , String username , String password , String verifypwd , ModelAndView model){ public ModelAndView resetPassword(String resetPasswordKey, String username, String password, String verifypwd,
Result result = iMemberService.resetPassword(resetPasswordKey , username , password , verifypwd); ModelAndView model) {
if(result.getCode() == 200){ // 调用会员服务的resetPassword方法传入重置密码关键信息、用户名、新密码以及确认新密码等参数进行密码重置操作返回包含操作结果信息的Result对象其中包含状态码、提示信息以及可能的业务数据等内容。
Result result = iMemberService.resetPassword(resetPasswordKey, username, password, verifypwd);
// 判断返回的Result对象中的状态码是否为200表示密码重置操作成功通常意味着新密码设置成功等情况符合预期。
if (result.getCode() == 200) {
// 如果密码重置成功,设置视图名称为"password/resetPwSuccess",表示要跳转到密码找回流程中的密码重置成功页面,用于告知用户密码重置操作已顺利完成。
model.setViewName("password/resetPwSuccess"); model.setViewName("password/resetPwSuccess");
}else{ } else {
// 如果密码重置失败,设置视图名称为"password/resetPassword",表示返回重置密码页面,以便用户重新输入正确的密码信息进行密码重置操作。
model.setViewName("password/resetPassword"); model.setViewName("password/resetPassword");
} }
// 返回包含视图名称的ModelAndView对象以便Spring的视图解析器根据视图名称查找并渲染相应的视图展示给用户。
return model; return model;
} }
/**
* GETaccountcheckAccountResult
* Result
*
* @param account
* @return Result
*/
@RequestMapping(value = "password/checkAccount", method = RequestMethod.GET) @RequestMapping(value = "password/checkAccount", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result checkAccount(String account){ public Result checkAccount(String account) {
return iMemberService.checkAccount(account); return iMemberService.checkAccount(account);
} }

@ -10,6 +10,7 @@ import org.springframework.web.servlet.ModelAndView;
import com.baomidou.mybatisplus.plugins.Page; import com.baomidou.mybatisplus.plugins.Page;
import com.tamguo.model.ChapterEntity; import com.tamguo.model.ChapterEntity;
import com.baomidou.mybatisplus.plugins.Page;
import com.tamguo.model.CourseEntity; import com.tamguo.model.CourseEntity;
import com.tamguo.model.QuestionEntity; import com.tamguo.model.QuestionEntity;
import com.tamguo.model.SubjectEntity; import com.tamguo.model.SubjectEntity;
@ -20,77 +21,155 @@ import com.tamguo.service.IQuestionService;
import com.tamguo.service.ISubjectService; import com.tamguo.service.ISubjectService;
import com.tamguo.util.Result; import com.tamguo.util.Result;
// 标识这是一个Spring的控制器类主要用于处理与试题相关的各种Web请求例如展示试题列表页面、试题详情页面以及获取特定试题信息等功能
// 通过调用相应的服务层接口获取数据并将数据添加到ModelAndView对象中返回给视图进行展示或者直接以JSON格式返回数据给前端如通过@ResponseBody注解的方法
@Controller @Controller
public class QuestionContrller { public class QuestionContrller {
// 自动注入IQuestionService用于处理试题相关的业务逻辑像根据章节ID获取试题列表、查找普通试题、获取推荐试题、按ID选择试题等操作都是通过该服务来完成。
@Autowired @Autowired
private IQuestionService iQuestionService; private IQuestionService iQuestionService;
// 自动注入IChapterService用于处理章节相关的业务逻辑例如根据章节ID查找章节、查找下一个章节、获取章节所属课程等操作在获取试题相关信息时可能会涉及章节信息的查询。
@Autowired @Autowired
private IChapterService iChapterService; private IChapterService iChapterService;
// 自动注入ISubjectService用于处理学科相关的业务逻辑例如根据课程所属学科ID查找学科信息等操作试题通常与特定学科相关查询试题相关信息时可能需要获取学科相关内容。
@Autowired @Autowired
private ISubjectService iSubjectService; private ISubjectService iSubjectService;
// 自动注入ICourseService用于处理课程相关的业务逻辑比如根据章节所属课程ID查找课程、获取课程所属学科等操作在获取试题相关信息时可能会涉及课程信息的查询。
@Autowired @Autowired
private ICourseService iCourseService; private ICourseService iCourseService;
/**
* GETIDoffsetlimit
*
* ModelAndView"questionList"ModelAndView
* "404"ModelAndView404
*
* @param chapterId
* @param offset
* @param limit
* @param model ModelAndView
* @return ModelAndView
*/
@RequestMapping(value = {"questionlist/{chapterId}-{offset}-{limit}"}, method = RequestMethod.GET) @RequestMapping(value = {"questionlist/{chapterId}-{offset}-{limit}"}, method = RequestMethod.GET)
public ModelAndView questionList(@PathVariable String chapterId , @PathVariable Integer offset , public ModelAndView questionList(@PathVariable String chapterId, @PathVariable Integer offset,
@PathVariable Integer limit , ModelAndView model){ @PathVariable Integer limit, ModelAndView model) {
try { try {
// 设置视图名称为"questionList",对应相应的试题列表页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。
model.setViewName("questionList"); model.setViewName("questionList");
// 根据传入的章节ID通过章节服务查询并获取对应的章节实体信息用于在试题列表页面展示试题所属章节等相关信息。
ChapterEntity chapter = iChapterService.findById(chapterId); ChapterEntity chapter = iChapterService.findById(chapterId);
// 通过章节所属的课程ID利用课程服务查询并获取对应的课程实体信息用于在试题列表页面展示试题所属课程等相关信息。
CourseEntity course = iCourseService.find(chapter.getCourseId()); CourseEntity course = iCourseService.find(chapter.getCourseId());
// 通过课程所属的学科ID利用学科服务查询并获取对应的学科实体信息用于在试题列表页面展示试题所属学科等相关信息。
SubjectEntity subject = iSubjectService.find(course.getSubjectId()); SubjectEntity subject = iSubjectService.find(course.getSubjectId());
// 根据章节的父章节ID通过章节服务查询并获取对应的父章节实体信息可能用于在试题列表页面展示章节的层级关系等相关信息具体根据前端展示需求确定
ChapterEntity parentChapter = iChapterService.findById(chapter.getParentId()); ChapterEntity parentChapter = iChapterService.findById(chapter.getParentId());
ChapterEntity nextChapter = iChapterService.findNextPoint(chapter.getParentId() , chapter.getOrders());
// 通过章节服务查找给定父章节下,当前章节顺序之后的下一个章节信息,可能用于在试题列表页面提供章节导航等功能(例如查看下一章的试题等情况,具体根据业务逻辑和前端需求确定)。
ChapterEntity nextChapter = iChapterService.findNextPoint(chapter.getParentId(), chapter.getOrders());
// 创建一个用于分页的Page对象设置当前页码根据传入的偏移量转换而来可能需要根据具体分页逻辑进行计算调整和每页显示的数量。
Page<QuestionEntity> page = new Page<>(); Page<QuestionEntity> page = new Page<>();
page.setCurrent(offset); page.setCurrent(offset);
page.setSize(limit); page.setSize(limit);
Page<QuestionEntity> questionList = iQuestionService.findByChapterId(chapterId , page);
// 调用试题服务的findByChapterId方法根据传入的章节ID和分页对象获取该章节下符合分页条件的试题列表数据返回包含试题列表以及分页相关信息的Page<QuestionEntity>对象。
Page<QuestionEntity> questionList = iQuestionService.findByChapterId(chapterId, page);
// 将查询到的学科实体信息添加到ModelAndView对象中以便在视图中展示试题所属学科等相关信息。
model.addObject("subject", subject); model.addObject("subject", subject);
// 将查询到的课程实体信息添加到ModelAndView对象中以便在视图中展示试题所属课程等相关信息。
model.addObject("course", course); model.addObject("course", course);
// 将查询到的章节实体信息添加到ModelAndView对象中以便在视图中展示试题所属章节等相关信息。
model.addObject("chapter", chapter); model.addObject("chapter", chapter);
model.addObject("parentChapter" , parentChapter);
model.addObject("nextChapter" , nextChapter); // 将查询到的父章节实体信息添加到ModelAndView对象中以便在视图中展示章节的层级关系等相关信息具体根据前端展示需求确定
model.addObject("parentChapter", parentChapter);
// 将查询到的下一个章节实体信息添加到ModelAndView对象中以便在视图中展示章节导航等相关信息例如查看下一章的试题等情况具体根据业务逻辑和前端需求确定
model.addObject("nextChapter", nextChapter);
// 将包含试题列表及分页信息的Page<QuestionEntity>对象添加到ModelAndView对象中以便在视图中展示具体的试题列表内容。
model.addObject("questionList", questionList); model.addObject("questionList", questionList);
// 将课程所属的学科ID添加到ModelAndView对象中可能用于前端页面的一些交互逻辑或者链接生成等用途具体根据前端需求确定
model.addObject("subjectId", course.getSubjectId()); model.addObject("subjectId", course.getSubjectId());
// 将课程的唯一标识符添加到ModelAndView对象中可能用于前端页面的一些交互逻辑或者链接生成等用途具体根据前端需求确定
model.addObject("courseId", course.getUid()); model.addObject("courseId", course.getUid());
// 返回包含视图名称和各种相关数据的ModelAndView对象以便进行视图渲染并展示给用户试题列表页面内容。
return model; return model;
} catch (Exception e) { } catch (Exception e) {
// 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。
model.setViewName("404"); model.setViewName("404");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出404页面展示给用户。
return model; return model;
} }
} }
/** /**
* 访 * GETuid
* @param uid * ModelAndView"question"ModelAndView
* @param model * "404"ModelAndView404
* @return *
* @param uid
* @param model ModelAndView
* @return ModelAndView
*/ */
@RequestMapping(value = {"/question/{uid}.html"}, method = RequestMethod.GET) @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 { try {
// 设置视图名称为"question",对应相应的试题详情页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。
model.setViewName("question"); model.setViewName("question");
// 根据传入的试题ID通过试题服务查询并获取对应的试题实体信息用于在试题详情页面展示试题的详细内容。
QuestionEntity question = iQuestionService.findNormalQuestion(uid); QuestionEntity question = iQuestionService.findNormalQuestion(uid);
// 根据试题实体中存储的试题类型代码通过QuestionType枚举类的方法获取对应的试题类型描述信息并设置到试题实体中
// 用于在试题详情页面展示更直观的试题类型名称(而不是原始的类型代码,提升用户体验)。
question.setQuestionType(QuestionType.getQuestionType(question.getQuestionType()).getDesc()); question.setQuestionType(QuestionType.getQuestionType(question.getQuestionType()).getDesc());
// 将查询到的试题实体信息包含更新后的试题类型描述添加到ModelAndView对象中以便在视图中展示试题的详细内容如试题题干、选项等信息。
model.addObject("question", question); model.addObject("question", question);
// 推荐试题 // 获取推荐试题列表调用试题服务的featuredQuestion方法传入当前试题的学科ID和课程ID获取相关的推荐试题列表
model.addObject("featuredQuestionList", iQuestionService.featuredQuestion(question.getSubjectId(),question.getCourseId())); // 并添加到ModelAndView对象中用于在试题详情页面展示相关的推荐试题内容方便用户查看其他类似或相关的试题。
model.addObject("featuredQuestionList", iQuestionService.featuredQuestion(question.getSubjectId(), question.getCourseId()));
// 返回包含视图名称和各种相关数据的ModelAndView对象以便进行视图渲染并展示给用户试题详情页面内容。
return model; return model;
} catch (Exception e) { } catch (Exception e) {
// 如果在查询相关数据过程中出现异常,将视图名称设置为"404",通常用于表示请求的资源不存在等错误情况。
model.setViewName("404"); model.setViewName("404");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出404页面展示给用户。
return model; return model;
} }
} }
/**
* GETuidselect
* Result便使
*
* @param uid
* @param model ModelAndView使
* @return ResultResult
*/
@RequestMapping(value = {"question/getQuestion/{uid}"}, method = RequestMethod.GET) @RequestMapping(value = {"question/getQuestion/{uid}"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result getQuestion(@PathVariable String uid , ModelAndView model){ public Result getQuestion(@PathVariable String uid, ModelAndView model) {
return Result.successResult(iQuestionService.select(uid)); return Result.successResult(iQuestionService.select(uid));
} }

@ -20,50 +20,96 @@ import com.tamguo.service.IMemberService;
import com.tamguo.util.Result; import com.tamguo.util.Result;
import com.tamguo.util.ShiroUtils; import com.tamguo.util.ShiroUtils;
// 标识这是一个Spring的控制器类主要用于处理用户注册相关的Web请求例如展示注册页面、检查用户名和手机号是否可用以及处理实际的注册提交操作等功能。
@Controller @Controller
public class RegisterController { public class RegisterController {
// 自动注入IMemberService用于调用会员相关的业务逻辑方法比如检查用户名是否已存在、检查手机号是否已注册、执行用户注册操作等这些操作都依赖于会员服务层提供的具体实现。
@Autowired @Autowired
private IMemberService iMemberService; private IMemberService iMemberService;
/**
* GET"register""register"JSPThymeleaf
*
*
* @param model ModelAndView
* @param session HttpSession使
* @return ModelAndView便Spring
*/
@RequestMapping(value = "/register", method = RequestMethod.GET) @RequestMapping(value = "/register", method = RequestMethod.GET)
public ModelAndView register(ModelAndView model , HttpSession session) { public ModelAndView register(ModelAndView model, HttpSession session) {
model.setViewName("register"); model.setViewName("register");
return model; return model;
} }
/**
* GETusernamecheckUsername
* ResultResult
*
* @param username 使
* @return Result
*/
@RequestMapping(value = "/checkUsername", method = RequestMethod.GET) @RequestMapping(value = "/checkUsername", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result checkUsername(String username){ public Result checkUsername(String username) {
return iMemberService.checkUsername(username); return iMemberService.checkUsername(username);
} }
/**
* GETmobilecheckMobile
* ResultResult
*
* @param mobile 使
* @return Result
*/
@RequestMapping(value = "/checkMobile", method = RequestMethod.GET) @RequestMapping(value = "/checkMobile", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result checkMobile(String mobile){ public Result checkMobile(String mobile) {
return iMemberService.checkMobile(mobile); return iMemberService.checkMobile(mobile);
} }
/**
* POST@RequestBodyJSONMemberEntityHttpSession
* registerResultcode
* 使ShiroHttpSessionResult
*
* @param member MemberEntityJSON
* @param session HttpSession便
* @return ResultResult200Result
*/
@RequestMapping(value = "/subRegister", method = RequestMethod.POST) @RequestMapping(value = "/subRegister", method = RequestMethod.POST)
@ResponseBody @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); Result result = iMemberService.register(member);
if(result.getCode() == 200) {
// 判断返回的Result对象中的状态码是否为200表示用户注册操作成功通常意味着用户信息已成功保存到数据库等情况符合预期此时尝试进行登录操作。
if (result.getCode() == 200) {
// 获取Shiro的Subject对象它代表了当前执行的用户主体用于后续进行登录认证等操作。
Subject subject = ShiroUtils.getSubject(); Subject subject = ShiroUtils.getSubject();
// 从注册成功返回的Result对象中获取包含注册后的用户信息的MemberEntity对象用于构建登录凭证用户名和密码
MemberEntity memberEntity = (MemberEntity) result.getResult(); MemberEntity memberEntity = (MemberEntity) result.getResult();
// 创建一个UsernamePasswordToken对象将注册后的用户名和用户注册时填写的密码封装进去作为登录认证的凭证传递给Shiro框架。
UsernamePasswordToken token = new UsernamePasswordToken(memberEntity.getUsername(), member.getPassword()); UsernamePasswordToken token = new UsernamePasswordToken(memberEntity.getUsername(), member.getPassword());
try { try {
// 通过Subject对象发起登录认证操作Shiro框架会根据配置的认证逻辑如从数据库查询用户信息并比对密码等进行验证。
subject.login(token); subject.login(token);
// 如果登录成功将登录后的用户信息保存到HttpSession中方便在后续的请求处理中获取当前登录用户的相关信息键为"currMember"。
session.setAttribute("currMember", ShiroUtils.getMember()); session.setAttribute("currMember", ShiroUtils.getMember());
} catch (UnknownAccountException e) { } catch (UnknownAccountException e) {
// 如果Shiro认证过程中抛出UnknownAccountException异常表示用户名不存在或者未找到对应的用户信息返回相应的错误提示信息的Result对象给前端。
return Result.result(201, null, "用户名或密码有误,请重新输入或找回密码"); return Result.result(201, null, "用户名或密码有误,请重新输入或找回密码");
} catch (IncorrectCredentialsException e) { } catch (IncorrectCredentialsException e) {
// 如果Shiro认证过程中抛出IncorrectCredentialsException异常表示密码错误返回相应的错误提示信息的Result对象给前端。
return Result.result(202, null, "用户名或密码有误,请重新输入或找回密码"); return Result.result(202, null, "用户名或密码有误,请重新输入或找回密码");
} catch (LockedAccountException e) { } catch (LockedAccountException e) {
// 如果Shiro认证过程中抛出LockedAccountException异常表示账号被锁定返回相应的错误提示信息的Result对象给前端。
return Result.result(203, null, "账号被锁定"); return Result.result(203, null, "账号被锁定");
} }
} }
// 返回包含注册结果信息的Result对象若注册成功且登录成功则返回正常的Result对象包含注册后的用户等相关成功信息若注册失败或者登录出现异常则返回相应的错误提示信息的Result对象前端可根据此结果进行相应处理。
return result; return result;
} }

@ -26,63 +26,121 @@ import com.tamguo.util.Result;
/** /**
* Controller - * Controller -
* SpringSubjectWeb
* JSON
* *
* @author candy.tam * @author candy.tam
*
*/ */
@Controller @Controller
public class SubjectController { public class SubjectController {
// 创建日志记录器,用于记录在处理各类请求过程中出现的关键信息(如正常的业务日志、异常信息等),方便后续查看日志进行调试、排查问题以及了解系统运行情况。
private Logger logger = LoggerFactory.getLogger(getClass()); private Logger logger = LoggerFactory.getLogger(getClass());
// 自动注入IChapterService用于处理章节相关的业务逻辑例如根据书籍ID查找课程对应的章节列表等操作在展示学科相关页面时可能需要获取章节信息进行展示。
@Autowired @Autowired
private IChapterService iChapterService; private IChapterService iChapterService;
// 自动注入IAreaService用于处理地区相关的业务逻辑比如查找根地区列表等操作可能在学科相关页面展示地区筛选信息或者其他与地区相关的功能中会用到该服务获取的数据。
@Autowired @Autowired
private IAreaService iAreaService; private IAreaService iAreaService;
// 自动注入ISubjectService用于处理学科相关的业务逻辑像根据学科ID查找学科实体、获取课程树结构数据、获取级联选择器形式的课程树数据等操作都是通过该服务来完成是处理学科相关请求的核心服务依赖。
@Autowired @Autowired
private ISubjectService iSubjectService; private ISubjectService iSubjectService;
// 自动注入IBookService用于处理书籍相关的业务逻辑例如根据课程ID查询相关书籍列表等操作在获取学科相关信息时可能会涉及书籍信息的查询进而基于书籍信息获取其他相关数据如章节信息等
@Autowired @Autowired
private IBookService iBookService; private IBookService iBookService;
/**
* GETIDsubjectId
* ModelAndView"subject"ModelAndView
* "500"ModelAndView500
*
* @param subjectId
* @param model ModelAndView
* @return ModelAndViewModelAndView
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@RequestMapping(value = {"subject/{subjectId}.html"}, method = RequestMethod.GET) @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 { try {
// 根据传入的学科ID通过学科服务查询并获取对应的学科实体信息用于在学科详细页面展示学科的基本信息、关联课程等相关内容。
SubjectEntity subject = iSubjectService.find(subjectId); SubjectEntity subject = iSubjectService.find(subjectId);
// 获取第一个科目
// 获取该学科下的第一个课程实体信息,这里假设取第一个课程作为某种默认展示或者后续处理的基础(具体业务逻辑可能需根据实际情况调整),
// 比如后续基于该课程查找相关书籍、章节等信息,方便在页面上展示与该学科相关的课程、书籍、章节等内容的关联关系。
CourseEntity course = subject.getCourseList().get(0); CourseEntity course = subject.getCourseList().get(0);
// 获取第一本书
// 通过条件查询,查找与当前课程相关的所有书籍列表,可能用于展示该课程下有哪些相关书籍等场景,以便在学科详细页面呈现更丰富的关联信息。
List<BookEntity> bookList = iBookService.selectList(Condition.create().eq("course_id", course.getUid())); List<BookEntity> bookList = iBookService.selectList(Condition.create().eq("course_id", course.getUid()));
// 获取书籍列表中的第一本图书实体信息(这里同样可能是基于某种默认展示或后续处理的考虑,取第一本作为代表,具体根据业务需求确定),
// 后续可能基于该书籍去查找对应的章节信息等内容,用于在学科详细页面展示课程下书籍包含的章节情况。
BookEntity book = bookList.get(0); BookEntity book = bookList.get(0);
// 通过章节服务,查询并获取当前书籍对应的章节列表信息,用于在学科详细页面展示该课程下书籍所包含的章节内容等,方便用户查看学科相关的具体知识章节情况。
List<ChapterEntity> chapterList = iChapterService.findCourseChapter(book.getUid()); List<ChapterEntity> chapterList = iChapterService.findCourseChapter(book.getUid());
model.setViewName("subject");
model.addObject("subject", subject); // 设置视图名称为"subject",对应相应的学科详细页面模板,后续会根据这个名称去查找并渲染对应的视图展示给用户。
model.addObject("course" , course); model.setViewName("subject");
model.addObject("courseList", subject.getCourseList());
model.addObject("chapterList" , chapterList); // 将查询到的学科实体信息添加到ModelAndView对象中以便在视图中展示学科的详细信息如学科名称、学科描述等内容。
model.addObject("areaList", iAreaService.findRootArea()); model.addObject("subject", subject);
return model;
// 将获取到的第一个课程实体信息添加到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) { } catch (Exception e) {
logger.error(e.getMessage() , e); // 如果在查询相关数据过程中出现异常,将异常信息记录到日志中,方便后续查看问题原因、进行调试等操作,记录的信息包括异常消息以及详细的异常堆栈信息。
logger.error(e.getMessage(), e);
// 将视图名称设置为"500",通常用于表示服务器内部出现错误的情况,意味着出现了未预期的异常导致无法正常处理请求并返回正确的视图内容。
model.setViewName("500"); model.setViewName("500");
// 返回包含错误视图名称的ModelAndView对象可能会渲染出500页面展示给用户告知出现了服务器内部错误。
return model; return model;
} }
} }
/**
* GETgetCourseTreeJSONArray
* Result便使
*
* @return ResultResultJSONArray
*/
@RequestMapping(value = {"subject/getCourseTree.html"}, method = RequestMethod.GET) @RequestMapping(value = {"subject/getCourseTree.html"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result getCourseTree(){ public Result getCourseTree() {
// 调用学科服务的getCourseTree方法获取课程树结构数据返回的数据格式为JSONArray其中包含了课程之间的层级关系等相关信息具体结构和内容由服务层实现决定
JSONArray list = iSubjectService.getCourseTree(); JSONArray list = iSubjectService.getCourseTree();
// 将获取到的课程树结构数据包装在表示成功的Result对象中返回给前端方便前端按照统一的格式进行处理Result对象中的数据字段存放实际的课程树信息这里就是JSONArray类型的list
return Result.successResult(list); return Result.successResult(list);
} }
// [{"value":"11","label":"北京市","children":[{"value":"1101","label":"市辖区"}]}] /**
* GETgetCourseCascaderTreeJSONArrayvaluelabelchildren
* Result便使便
*
* @return ResultResultJSONArray
*/
@RequestMapping(value = {"subject/getCourseCascaderTree"}, method = RequestMethod.GET) @RequestMapping(value = {"subject/getCourseCascaderTree"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Result getCourseCascaderTree() { public Result getCourseCascaderTree() {
// 调用学科服务的getCourseCascaderTree方法获取级联选择器形式的课程树数据返回的数据格式为JSONArray其结构符合级联选择器所需的格式例如示例中展示的包含节点的value、label以及子节点children等信息
JSONArray list = iSubjectService.getCourseCascaderTree(); JSONArray list = iSubjectService.getCourseCascaderTree();
// 将获取到的级联选择器形式的课程树数据包装在表示成功的Result对象中返回给前端方便前端按照统一的格式进行处理Result对象中的数据字段存放实际的课程树信息这里就是JSONArray类型的list
return Result.successResult(list); return Result.successResult(list);
} }
} }

@ -26,86 +26,167 @@ import com.tamguo.dao.redis.CacheService;
import com.tamguo.util.DateUtils; import com.tamguo.util.DateUtils;
import com.tamguo.util.Setting; import com.tamguo.util.Setting;
// 标识这是一个Spring的控制器类主要用于处理与UEditor相关的Web请求例如返回UEditor的配置信息以及处理图片上传等功能
// 在图片上传过程中涉及文件的存储操作、根据日期生成文件路径、利用缓存生成唯一文件名编号等逻辑,同时对操作过程中的异常进行了相应处理并返回合适的结果给前端。
@Controller @Controller
public class UEditorController { public class UEditorController {
// 创建日志记录器用于记录在处理UEditor相关请求过程中出现的关键信息如正常的业务日志、文件上传成功或失败信息、异常信息等方便后续查看日志进行调试、排查问题以及了解系统运行情况。
private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); private Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
// 通过@Value注解注入配置文件中配置的文件存储路径属性值该路径用于指定上传文件在服务器端存储的基础目录位置后续会根据日期等信息进一步构建具体的文件存储子目录。
@Value("${file.storage.path}") @Value("${file.storage.path}")
private String fileStoragePath; private String fileStoragePath;
// 自动注入Setting对象该对象可能包含了系统的一些全局设置信息例如域名等相关配置在处理文件上传后的文件访问路径等相关逻辑时可能会用到其中的配置数据。
@Autowired @Autowired
private Setting setting; private Setting setting;
// 自动注入CacheService用于与缓存系统进行交互在这里主要是利用缓存来生成UEditor上传文件的唯一编号以保证文件名的唯一性便于文件管理和区分不同时间上传的文件。
@Autowired @Autowired
private CacheService cacheService; private CacheService cacheService;
// 定义一个表示UEditor文件编号无格式的常量字符串用于后续格式化生成唯一编号时作为格式模板这里"00000"表示生成的编号会按照五位数字进行格式化填充前面补0具体用途在生成文件名编号逻辑中体现。
private static final String UEDITOR_NO_FORMAT = "00000"; private static final String UEDITOR_NO_FORMAT = "00000";
private static final String UEDITOR_PREFIX = "UEDITOR";
// 定义一个UEditor相关的文件名前缀常量字符串用于构建上传文件的唯一文件名方便在文件系统中对UEditor上传的文件进行统一标识和区分与后面生成的编号等组合形成完整的文件名。
private static final String UEDITOR_PREFIX = "UEDITOR";
@RequestMapping(value="/ueditor") /**
@ResponseBody * UEditorUEditorJSONUEditorConfig.UEDITOR_CONFIGJSONObject
public JSONObject ueditor(HttpServletRequest request) { * UEditor使
return JSONObject.parseObject(UEditorConfig.UEDITOR_CONFIG); *
} * @param request HttpServletRequest使
* @return JSONObjectUEditor
*/
@RequestMapping(value = "/ueditor")
@ResponseBody
public JSONObject ueditor(HttpServletRequest request) {
return JSONObject.parseObject(UEditorConfig.UEDITOR_CONFIG);
}
@RequestMapping(value="/imgUpload") /**
@ResponseBody * MultipartFileupfile
public Ueditor imgUpload(MultipartFile upfile) throws IOException { * 访URLUeditorUeditor
if (!upfile.isEmpty()) { *
* @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; InputStream in = null;
OutputStream out = null; OutputStream out = null;
try { try {
// 根据当前日期年、月、日构建文件存储的子目录路径将其与配置的文件存储基础路径fileStoragePath拼接起来形成完整的文件存储目录路径
// 这样可以按照日期对上传的文件进行分类存储,便于管理和查找不同时间上传的文件。
String path = fileStoragePath + DateUtils.format(new Date(), "yyyyMMdd"); String path = fileStoragePath + DateUtils.format(new Date(), "yyyyMMdd");
File dir = new File(path); File dir = new File(path);
// 判断文件存储目录是否存在,如果不存在则创建该目录,确保后续可以将文件保存到正确的目录位置。
if (!dir.exists()) if (!dir.exists())
dir.mkdirs(); dir.mkdirs();
// 调用getUEditorNo方法生成一个唯一的文件名编号该编号结合文件原始名称的后缀通过截取原始文件名中最后一个"."之后的部分获取后缀),构建出完整的服务器端存储文件名,
// 以此保证文件名在整个系统中的唯一性,便于文件管理和区分不同的上传文件。
String fileName = this.getUEditorNo() + upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf(".")); String fileName = this.getUEditorNo() + upfile.getOriginalFilename().substring(upfile.getOriginalFilename().lastIndexOf("."));
File serverFile = new File(dir + File.separator + fileName); File serverFile = new File(dir + File.separator + fileName);
// 获取上传文件的输入流,用于读取文件内容,后续将通过该输入流把文件内容写入到服务器端的目标文件中。
in = upfile.getInputStream(); in = upfile.getInputStream();
// 创建一个指向服务器端目标文件的输出流,用于将从上传文件读取到的内容写入到该文件中,实现文件保存到服务器的操作。
out = new FileOutputStream(serverFile); out = new FileOutputStream(serverFile);
// 创建一个字节数组缓冲区用于批量读取和写入文件内容每次读取1024字节的数据提高文件读写效率避免逐个字节读写的低效率情况
byte[] b = new byte[1024]; byte[] b = new byte[1024];
int len = 0; int len = 0;
// 通过循环不断从输入流中读取数据到字节数组缓冲区每次最多读取1024字节直到读取完整个文件内容即读取的字节数小于等于0表示已读完
// 然后将缓冲区中的数据写入到输出流对应的服务器端文件中,实现文件内容的复制保存操作。
while ((len = in.read(b)) > 0) { while ((len = in.read(b)) > 0) {
out.write(b, 0, len); out.write(b, 0, len);
} }
// 关闭输出流,释放相关资源,确保文件写入操作完成后正确关闭资源,避免资源泄漏等问题。
out.close(); out.close();
// 关闭输入流,释放相关资源,确保文件读取操作完成后正确关闭资源,避免资源泄漏等问题。
in.close(); in.close();
// 将服务器端保存文件的绝对路径信息记录到日志中,方便后续查看文件实际存储位置以及排查文件相关的问题(如文件是否保存成功等情况)。
logger.info("Server File Location=" + serverFile.getAbsolutePath()); logger.info("Server File Location=" + serverFile.getAbsolutePath());
Ueditor ueditor = new Ueditor(); // 创建一个Ueditor对象用于返回文件上传的结果信息给前端。
ueditor.setState("SUCCESS"); Ueditor ueditor = new Ueditor();
ueditor.setUrl(setting.domain + "files" + "/" +DateUtils.format(new Date(), "yyyyMMdd") + "/" + fileName); // 设置文件上传状态为"SUCCESS",表示文件上传成功,前端可以根据该状态进行相应的提示信息展示等处理(例如显示上传成功的提示框)。
return ueditor; 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) { } catch (Exception e) {
// 如果在文件上传过程中出现异常如文件保存失败、流操作异常等情况创建一个表示错误状态的Ueditor对象用于返回错误信息给前端。
Ueditor ueditor = new Ueditor(); Ueditor ueditor = new Ueditor();
ueditor.setState("ERROR"); // 设置文件上传状态为"ERROR",表示文件上传失败,前端可以根据该状态进行相应的提示信息展示(例如显示上传失败的提示框)。
ueditor.setTitle("上传失败"); ueditor.setState("ERROR");
return ueditor; // 设置错误提示标题为"上传失败",用于更详细地告知前端用户文件上传出现问题的大致情况,前端可根据此标题进行更具体的错误提示展示(具体展示逻辑由前端决定)。
ueditor.setTitle("上传失败");
// 返回包含错误状态及错误提示标题的Ueditor对象给前端告知文件上传失败及失败原因通过标题提示
return ueditor;
} finally { } finally {
if (out != null) { // 在finally块中确保输出流资源能够正确关闭避免因异常等情况导致资源未释放的问题先判断输出流是否不为空如果不为空则关闭输出流并将其置为null表示资源已释放。
if (out!= null) {
out.close(); out.close();
out = null; out = null;
} }
if (in != null) { // 在finally块中确保输入流资源能够正确关闭避免因异常等情况导致资源未释放的问题先判断输入流是否不为空如果不为空则关闭输入流并将其置为null表示资源已释放。
if (in!= null) {
in.close(); in.close();
in = null; in = null;
} }
} }
} else { } else {
// 如果上传的文件为空创建一个表示错误状态的Ueditor对象用于返回错误信息给前端。
Ueditor ueditor = new Ueditor(); Ueditor ueditor = new Ueditor();
ueditor.setState("ERROR"); // 设置文件上传状态为"ERROR",表示文件上传失败,前端可以根据该状态进行相应的提示信息展示(例如显示上传失败的提示框)。
ueditor.setTitle("File is empty"); ueditor.setState("ERROR");
return ueditor; // 设置错误提示标题为"File is empty",明确告知前端用户上传的文件为空,前端可根据此标题进行相应的错误提示展示(具体展示逻辑由前端决定)。
ueditor.setTitle("File is empty");
// 返回包含错误状态及错误提示标题的Ueditor对象给前端告知文件上传失败及失败原因文件为空
return ueditor;
} }
} }
/**
* UEditor"yyyyMM"
* UEDITOR_PREFIXCacheService
* UEDITOR_NO_FORMAT0
*
* @return UEditor便
*/
private String getUEditorNo() { private String getUEditorNo() {
// 创建一个SimpleDateFormat对象用于按照"yyyyMM"格式对日期进行格式化,即获取当前日期的年和月信息,用于构建与日期相关的唯一编号部分。
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
String format = sdf.format(new Date()); String format = sdf.format(new Date());
// 创建一个DecimalFormat对象使用定义的UEDITOR_NO_FORMAT常量作为格式化模板用于将后续生成的自增编号按照五位数字的格式进行格式化不足五位前面补0保证编号格式的一致性和唯一性。
DecimalFormat df = new DecimalFormat(UEDITOR_NO_FORMAT); DecimalFormat df = new DecimalFormat(UEDITOR_NO_FORMAT);
// 构建缓存中的键将固定的UEDITOR_PREFIX前缀与当前日期格式字符串format拼接起来形成一个唯一标识当前月份的UEditor文件编号相关的键用于在缓存中进行计数操作。
String key = UEDITOR_PREFIX + format; String key = UEDITOR_PREFIX + format;
// 通过缓存服务CacheService对构建的键对应的值进行自增操作每次调用该方法时对应键的值会在原来基础上加1以此生成顺序递增且唯一的编号值返回自增后的编号值。
Long incr = cacheService.incr(key); Long incr = cacheService.incr(key);
// 将自增后的编号值按照定义的格式通过DecimalFormat进行格式化进行处理与固定的UEDITOR_PREFIX前缀再次拼接形成完整的唯一文件名编号用于后续构建上传文件的文件名保证文件名的唯一性。
String avatorNo = UEDITOR_PREFIX + df.format(incr); String avatorNo = UEDITOR_PREFIX + df.format(incr);
return avatorNo; return avatorNo;
} }

@ -15,18 +15,34 @@ import com.tamguo.model.TeacherEntity;
import com.tamguo.service.ITeacherService; import com.tamguo.service.ITeacherService;
import com.tamguo.util.Result; import com.tamguo.util.Result;
// 标识这是一个Spring的控制器类用于处理与教师相关的Web请求并返回相应的视图或数据
@Controller @Controller
public class JoinusController { public class JoinusController {
// 自动注入ITeacherService用于处理教师相关的业务逻辑比如根据手机号获取教师信息、教师注册加入等操作
@Autowired @Autowired
private ITeacherService iTeacherService; private ITeacherService iTeacherService;
/**
* GET"teacher/joinus"
*
* @param model ModelAndView
* @param session HttpSession使
* @return ModelAndView便
*/
@RequestMapping(value = "teacher/joinus", method = RequestMethod.GET) @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"); model.setViewName("teacher/joinus");
return model; return model;
} }
/**
* POSTMapmobileverifyCode
* Result
*
* @param param Map<String, Object>
* @return Result
*/
@RequestMapping(value = "teacher/info", method = RequestMethod.POST) @RequestMapping(value = "teacher/info", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Result getTeacher(@RequestBody Map<String, Object> param) { public Result getTeacher(@RequestBody Map<String, Object> param) {
@ -36,6 +52,13 @@ public class JoinusController {
return result; return result;
} }
/**
* POSTTeacherEntityjoinus
* ResultResult
*
* @param teacher TeacherEntity
* @return Result
*/
@RequestMapping(value = "teacher/joinus", method = RequestMethod.POST) @RequestMapping(value = "teacher/joinus", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public Result teacherJoinus(@RequestBody TeacherEntity teacher) { public Result teacherJoinus(@RequestBody TeacherEntity teacher) {

Loading…
Cancel
Save