博主开学进入大三下学期,目前备考计算机研究生,但是很坦诚地说,不一定能考上。因此,利用考研复习之余练习自己的后端开发技术也成了一种必要,(如果)考研失败坚决不二战,去外包当个crud boy也挺好。
定义mapper接口,负责与数据库进行交互设计
定义service接口和service接口实现类,负责业务模块的逻辑应用设计
定义controller类,负责每个具体的业务模块流程控制
负责前台页面的展示
IntelliJ IDEA 、Navicat Premium 15
本项目主要记录后端内容,前端部分简要阐述或省略
<dependencies>
<!--SpringMVC核心依赖包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
<!--Freemarker依赖包-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<!--Freemarker支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.3</version>
</dependency>
<!--json序列化包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
<!--Mybatis依赖包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!--Mybatis与Spring整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<!--单元测试包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--javax.servlet包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--Mybatis-Plus包-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!--Kaptcha验证码包-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<!--加密/解密包-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<!--Spring MVC文件上传底层包-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--Json Html解析包-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
</dependencies>
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</init-param>
<!--在Web应用启动时自动创建Spring Ioc容器,并初始化DispatcherServlet-->
<load-on-startup>0</load-on-startup>
</servlet>
<!--为DispatcherServlet映射url-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--解决Get、post请求的中文乱码-->
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*
<!--开启SpringMVC注解模式-->
<context:component-scan base-package="com.xiaopeng"/>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!--解决响应的中文乱码-->
<value>text/html;charset=utf-8</value>
<!--json序列化输出配置-->
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler/>
<!--配置Freemarker模板引擎-->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl"/>
<property name="freemarkerSettings">
<props>
<prop key="defaultEncoding">utf-8</prop>
</props>
</property>
</bean>
<!-- 配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="contentType" value="text/html;charset=utf-8"/>
<property name="suffix" value=".ftl"/>
</bean>
<!--Mybatis与Spring的整合配置-->
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/xiaopeng_reader?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="initialSize" value="10"/>
<property name="maxActive" value="20"/>
</bean>
<!--创建sessionFactory对象-->
<!--bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"-->
<bean id="sessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mappers/*.xml"/>
<!--Mybatis配置文件地址-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--配置Mapper扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiaopeng.reader.mapper"/>
</bean>
<!--声明式事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--配置Kaptcha验证码-->
<bean id="kaptchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
<property name="config">
<bean class="com.google.code.kaptcha.util.Config">
<constructor-arg>
<props>
<!--验证码图片不生成边框-->
<prop key="kaptcha.border">no</prop>
<!--验证码图片宽度150像素-->
<prop key="kaptcha.image.width">100</prop>
<!--验证码图片字体颜色为浅蓝色-->
<prop key="kaptcha.textproducer.font.color">blue</prop>
<!--每个字符最大占用50像素-->
<prop key="kaptcha.textproducer.font.size">50</prop>
<!--验证码包含4个字符-->
<prop key="kaptcha.textproducer.char.length">4</prop>
</props>
</constructor-arg>
</bean>
</property>
</bean>
<!--开启spring task任务的注解模式-->
<task:annotation-driven/>
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<plugins>
<plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></plugin>
</plugins>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{
HH:mm:ss}%-5level[%thread]%logger{
30} - %msg%n</pattern>
<charset>UTF=8</charset>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="console"/>
</root>
</configuration>
@TableName("category")
public class Category {
@TableId(type= IdType.AUTO)
private Long categoryId;
private String categoryName;
public Long getCategoryId() {
return categoryId;
}
public void setCategoryId(Long categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
继承BaseMapper接口,拥有基类增删改查方法
public interface CategoryMapper extends BaseMapper<Category> {
}
关联CategoryMapper接口,从而对数据库进行操作
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopeng.reader.mapper.CategoryMapper"></mapper>
自定义抽象方法selectAll,由子类实现其抽象方法
public interface CategoryService {
public List<Category> selectAll();
}
实现CategoryService接口的抽象方法:
通过categoryMapper接口的selectList方法得到category表
自定义selectAll方法返回category表
@Service("categoryService")
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public class CategoryServiceImpl implements CategoryService {
@Resource
private CategoryMapper categoryMapper;
public List<Category> selectAll(){
List<Category> list=categoryMapper.selectList(new QueryWrapper<Category>());
return list;
}
}
调用CategoryService接口向上转型的selectAll方法得到category表
自定义showIndex方法返回category表数据
@Controller
public class BookController {
@Resource
private CategoryService categoryService;
@GetMapping("/")
public ModelAndView showIndex(){
ModelAndView mav=new ModelAndView("/index");
List<Category> categoryList=categoryService.selectAll();
mav.addObject("categoryList",categoryList);
return mav;
}
}
<div class="col-8 mt-2">
<span data-category="-1" style="cursor: pointer" class="highlight font-weight-bold category">全部</span>
|
<#list categoryList as category>
<a style="cursor: pointer" data-category="${category.categoryId}" class="text-black-50 font-weight-bold category">${
category.categoryName}</a>
<#if category_has_next>|</#if>
</#list>
</div>
实现功能:
显示动态数据:武侠,玄幻,都市,二次元
显示效果:
自定义抽象方法paging,由子类实现其抽象方法
public interface BookService {
public IPage<Book> paging(Long categoryId,String order,Integer page,Integer rows);
}
实现BookService接口的抽象方法:
通过BookMapper接口的selectPage方法和条件构造器筛选得到分页对象
自定义paging方法返回分页对象
@Service("BookService")
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public class BookServiceImpl implements BookService {
@Resource
private BookMapper bookMapper;
public IPage<Book> paging(Long categoryId,String order,Integer page, Integer rows){
Page<Book> p=new Page<Book>(page,rows);
QueryWrapper<Book> queryWrapper=new QueryWrapper<Book>();
if(categoryId!=null&&categoryId!=-1){
queryWrapper.eq("category_id",categoryId);
}
if(order!=null){
if(order.equals("quantity")){
queryWrapper.orderByDesc("evaluation_quantity");
}else if(order.equals("score")){
queryWrapper.orderByDesc("evaluation_score");
}
}
IPage<Book> pageObject=bookMapper.selectPage(p,queryWrapper);
return pageObject;
}
调用BookService接口向上转型的paging方法得到分页对象
自定义selectBook方法返回分页对象的json格式数据
@Resource
private BookService bookService;
@GetMapping("/books")
@ResponseBody
public IPage<Book> selectBook(Long categoryId,String order,Integer p){
if(p==null)p=1;
IPage<Book> pageObject=bookService.paging(categoryId,order,p,3);
return pageObject;
}
<script>
$.fn.raty.defaults.path="../../resources/raty/lib/images";
function loadMore(isReset){
if(isReset==true){
$("#bookList").html("");
$("#nextPage").val(1);
}
var nextPage=$("#nextPage").val();
var categoryId=$("#categoryId").val();
var order=$("#order").val();
$.ajax({
url:"/books",
data:{
p:nextPage,"categoryId":categoryId,"order":order},
type:"get",
dataType:"json",
success:function (json) {
console.info(json);
var list=json.records;
for(var i=0;i<list.length;i++){
var bookRecords=json.records[i];
var html=template("template",bookRecords);
console.info(html);
$("#bookList").append(html);
}
$(".stars").raty({
readOnly:true});
if(json.current<json.pages){
$("#nextPage").val(parseInt(json.current)+1);
$("#btnMore").show();
$("#divNoMore").hide();
}else{
$("#btnMore").hide();
$("#divNoMore").show();
}
}
})
}
$(function () {
loadMore(true);
})
$(function () {
$("#btnMore").click(function () {
loadMore();
})
$(".category").click(function () {
$(".category").removeClass("highlight");
$(".category").addClass("text-black-50");
$(this).addClass("highlight")
var categoryId=$(this).data("category");
$("#categoryId").val(categoryId);
loadMore(true);
})
$(".order").click(function () {
$(".order").removeClass("highlight");
$(".order").addClass("text-black-50");
$(this).addClass("highlight")
var order=$(this).data("order");
$("#order").val(order);
loadMore(true);
})
})
</script>
实现功能:
1.客户端访问时默认显示首页,每页记录数为3条
2.点击加载更多时:p+=1,局部更新页面并显示下一页的3条小说信息
3.小说信息由Book表的数据动态填充,星型组件随着评分的变化动态更新
4.武侠、玄幻、都市、二次元和按热度、按评分用于筛选和排序小说.前者按照categoryId,后者按照evaluationScore和evaluationQuantity进行筛选和排序,比如点击二次元再点击按评分,会显示对应小说类型的图书并按照评分标准进行降序排列
显示效果:
自定义抽象方法selectById,由子类实现其抽象方法
public Book selectById(Long bookId);
实现BookService接口的抽象方法:
通过BookMapper接口的selectById方法得到对应bookId的book表记录
自定义selectById方法返回对应bookId的book表记录
public Book selectById(Long bookId){
Book book=bookMapper.selectById(bookId);
return book;
}
调用BookService的selectById方法得到对应bookId的Book表记录
自定义showDetail方法返回对应bookId的book表数据
@GetMapping("/book/{id}")
public ModelAndView showDetail(@PathVariable("id") Long id){
Book book=bookService.selectById(id);
ModelAndView mav=new ModelAndView("/detail");
mav.addObject("book",book);
return mav;
}
实现功能:
接收对应bookId的Book表数据并填充到视图中
显示效果:
自定义抽象方法selectById,由子类实现其抽象方法
public List<Evaluation> selectById(Long bookId);
@TableField(exist = false)
private Book book;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
@TableField(exist = false)
private Member member;
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
}
实现EvaluationService接口的抽象方法:
通过EvaluationMapper接口的selectById方法得到对应bookId的有效evaluation表
自定义selectById方法返回有效evaluation表
@Resource
private EvaluationMapper evaluationMapper;
@Resource
private MemberMapper memberMapper;
@Resource
private BookMapper bookMapper;
@Service("EvaluationService")
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public List<Evaluation> selectById(Long bookId){
Book book=bookMapper.selectById(bookId);
QueryWrapper<Evaluation> queryWrapper=new QueryWrapper<Evaluation>();
queryWrapper.eq("book_id",bookId);
queryWrapper.eq("state","enable");
queryWrapper.orderByDesc("create_time");
List<Evaluation> evaluationList=evaluationMapper.selectList(queryWrapper);
for(Evaluation eva:evaluationList){
Member member=memberMapper.selectById(eva.getMemberId());
eva.setMember(member);
eva.setBook(book);
}
return evaluationList;
}
}
调用BookService的selectById方法得到对应bookId的book表记录
调用EvaluationService的selectById方法得到对应bookId的evaluation表
自定义showDetail方法返回对应bookId的book表记录和evaluation表
@Resource
private EvaluationService evaluationService;
@GetMapping("/book/{id}")
public ModelAndView showDetail(@PathVariable("id") Long id){
Book book=bookService.selectById(id);
List<Evaluation> evaluationList=evaluationService.selectById(id);
ModelAndView mav=new ModelAndView("/detail");
mav.addObject("book",book);
mav.addObject("evaluationList",evaluationList);
return mav;
}
实现功能:
接收对应bookId的有效evaluation表数据并填充到视图中
显示效果:
自定义createVerifyCode方法返回验证码图片
@Controller
public class KaptchaController {
@Resource
private Producer kaptchaProducer;
@GetMapping("/verify_code")
public void createVerifyCode(HttpServletRequest request, HttpServletResponse response){
response.setDateHeader("Expires",0);
response.setHeader("Cache-Control","no-store,no-cache,must-revalidate");
response.setHeader("Cache-Control","post-check=0,pre-check=0");
response.setHeader("Pragma","no-cache");
response.setContentType("image/png");
String verifyCode=kaptchaProducer.createText();
request.getSession().setAttribute("kaptchaVerifyCode",verifyCode);
BufferedImage image=kaptchaProducer.createImage(verifyCode);
ServletOutputStream out=null;
try {
out=response.getOutputStream();
ImageIO.write(image,"png",out);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class BussinessException extends RuntimeException{
private String code;
private String msg;
public BussinessException(String code,String msg){
super(code+":"+msg);
this.code=code;
this.msg=msg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
算法:
将密码字符串拆成一个个字符,加密后产生一个个新的字符,再将一个个新的字符组装起来
自定义md5Digest方法返回加密后的字符串
public class MD5Utils {
public static String md5Digest(String source,Integer salt){
char[] c=source.toCharArray();
for(int i=0;i<c.length;i++){
c[i]=(char)(c[i]+salt);
}
String target=new String(c);
String md5=DigestUtils.md5Hex(target);
return md5;
}
}
public interface MemberService {
/**
* 用户注册,创建新用户
* @param username 用户名
* @param password 密码
* @param nickname 昵称
* @return 新用户对象
*/
public Member createMember(String username,String password,String nickname);
/**
* 验证登录
* @param username 用户名
* @param password 密码
* @return
*/
public Member checkLogin(String username,String password);
/**
*
* @param memberId 用户编号
* @param bookId 图书编号
* @return 阅读状态对象
*/
public MemberReadState selectMemberReadState(Long memberId,Long bookId);
/**
*更新阅读状态
* @param memberId 用户编号
* @param bookId 图书编号
* @param readState 阅读状态
* @return 阅读状态对象
*/
public MemberReadState updateMemberReadState(Long memberId,Long bookId,Integer readState);
/**
*发布新评论
* @param memberId 会员编号
* @param bookId 图书编号
* @param score 评分
* @param content 评价内容
* @return
*/
public Evaluation evaluate(Long memberId,Long bookId,Integer score,String content);
/**
* 评论点赞功能
* @param evaluationId 评论编号
* @return评论对象
*/
public Evaluation enjoy(Long evaluationId);
}
@Service("MemberService")
@Transactional
public class MemberServiceImpl implements MemberService {
@Resource
private MemberMapper memberMapper;
@Resource
private MemberReadStateMapper memberReadStateMapper;
@Resource
EvaluationMapper evaluationMapper;
public Member createMember(String username, String password, String nickname) {
QueryWrapper<Member> queryWrapper=new QueryWrapper<Member>();
queryWrapper.eq("username",username);
List<Member> members=memberMapper.selectList(queryWrapper);
if(members.size()>0){
throw new BussinessException("Mistake01","用户名已存在");
}
Member member=new Member();
member.setUsername(username);
member.setNickname(nickname);
int salt=new Random().nextInt(1000)+1000;
String md5=MD5Utils.md5Digest(password,salt);
member.setPassword(md5);
member.setSalt(salt);
member.setCreateTime(new Date());
memberMapper.insert(member);
return member;
}
public Member checkLogin(String username,String password){
QueryWrapper<Member>queryWrapper=new QueryWrapper<Member>();
queryWrapper.eq("username",username);
Member member=memberMapper.selectOne(queryWrapper);
if(member==null){
throw new BussinessException("Mistake02","用户不存在");
}
String md5=MD5Utils.md5Digest(password,member.getSalt());
if(!md5.equals(member.getPassword())){
throw new BussinessException("Mistake03","密码不正确");
}
return member;
}
public MemberReadState selectMemberReadState(Long memberId,Long bookId){
QueryWrapper<MemberReadState> queryWrapper=new QueryWrapper<MemberReadState>();
queryWrapper.eq("book_id",bookId);
queryWrapper.eq("member_id",memberId);
MemberReadState memberReadState=memberReadStateMapper.selectOne(queryWrapper);
return memberReadState;
}
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public MemberReadState updateMemberReadState(Long memberId, Long bookId, Integer readState) {
QueryWrapper<MemberReadState> queryWrapper=new QueryWrapper<MemberReadState>();
queryWrapper.eq("book_id",bookId);
queryWrapper.eq("member_id",memberId);
MemberReadState memberReadState=memberReadStateMapper.selectOne(queryWrapper);
if(memberReadStateMapper==null){
memberReadState= new MemberReadState();
memberReadState.setMemberId(memberId);
memberReadState.setBookId(bookId);
memberReadState.setReadState(readState);
memberReadState.setCreateTime(new Date());
memberReadStateMapper.insert(memberReadState);
}else{
memberReadState.setReadState(readState);
memberReadStateMapper.updateById(memberReadState);
}
return memberReadState;
}
public Evaluation evaluate(Long memberId, Long bookId, Integer score, String content) {
Evaluation evaluation=new Evaluation();
evaluation.setMemberId(memberId);
evaluation.setBookId(bookId);
evaluation.setScore(score);
evaluation.setContent(content);
evaluation.setCreateTime(new Date());
evaluation.setState("enable");
evaluation.setEnjoy(0);
evaluationMapper.insert(evaluation);
return evaluation;
}
public Evaluation enjoy(Long evaluationId) {
Evaluation eva=evaluationMapper.selectById(evaluationId);
eva.setEnjoy(eva.getEnjoy()+1);
evaluationMapper.updateById(eva);
return eva;
}
}
@Controller
public class MemberController {
@Resource
private MemberService memberService;
@GetMapping("/register.html")
public ModelAndView showRegister(){
return new ModelAndView("/register");
}
@GetMapping("/login.html")
public ModelAndView showLogin(){
return new ModelAndView("/login");
}
@PostMapping("/register")
@ResponseBody
public Map register(String vc, String username, String password, String nickname, HttpServletRequest request){
String verifyCode=(String)request.getSession().getAttribute("kaptchaVerifyCode");
Map result=new HashMap();
if(vc==null || verifyCode==null ||!vc.equalsIgnoreCase(verifyCode)){
result.put("code","vcMistake");
result.put("msg","验证码错误");
}else{
try {
memberService.createMember(username,password,nickname);
result.put("code","vcCorrect");
result.put("msg","注册成功");
}catch (BussinessException bec){
bec.printStackTrace();
result.put("code",bec.getCode());
result.put("msg",bec.getMsg());
}
}
return result;
}
@PostMapping("/check_login")
@ResponseBody
public Map checkLogin(String username, String password, String vc, HttpSession session){
String verifyCode=(String)session.getAttribute("kaptchaVerifyCode");
Map result=new HashMap();
if(vc==null || verifyCode==null ||!vc.equalsIgnoreCase(verifyCode)){
result.put("code","vcMistake");
result.put("msg","验证码错误");
}else {
try {
Member member= memberService.checkLogin(username,password);
session.setAttribute("loginMember",member);
result.put("code","loginCorrect");
result.put("msg","登录成功");
}catch (BussinessException bec){
bec.printStackTrace();
result.put("code",bec.getCode());
result.put("msg",bec.getMsg());
}
}
return result;
}
@PostMapping("/update_read_state")
@ResponseBody
public Map updateReadState(Long memberId, Long bookId, Integer readState){
Map result=new HashMap();
try {
memberService.updateMemberReadState(memberId,bookId,readState);
result.put("code","updateCorrect");
result.put("msg","更新成功");
}catch (BussinessException bec){
bec.printStackTrace();
result.put("code",bec.getCode());
result.put("msg",bec.getMsg());
}
return result;
}
@PostMapping("/evaluate")
@ResponseBody
public Map evaluate(Long memberId, Long bookId, Integer score, String content){
Map result=new HashMap();
try {
Evaluation eva=memberService.evaluate(memberId,bookId,score,content);
result.put("code","submitCorrect");
result.put("msg","更新成功");
result.put("evaluation",eva);
}catch (BussinessException bec){
bec.printStackTrace();
result.put("code",bec.getCode());
result.put("msg",bec.getMsg());
}
return result;
}
@PostMapping("/enjoy")
@ResponseBody
public Map enjoy(Long evaluationId){
Map result=new HashMap();
try {
Evaluation evaluation=memberService.enjoy(evaluationId);
result.put("code","enjoyCorrect");
result.put("msg","点赞成功");
result.put("evaluation",evaluation);
}catch (BussinessException bec){
bec.printStackTrace();
result.put("code",bec.getCode());
result.put("msg",bec.getMsg());
}
return result;
}
}
实现功能:
1.未登录状态下点击评价之类的按钮都会提示去登录
2.注册功能
3.登录功能
4.用户阅读状态变更和点赞数量变更
5.用户评论
public interface BookMapper extends BaseMapper<Book> {
/**
* 更新图书评分和评价数量
*/
public void updateEvaluation();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiaopeng.reader.mapper.BookMapper">
<update id="updateEvaluation">
update book b set evaluation_score=(
select ifnull(avg(score),0) from evaluation where book_id=b.book_id
and state='enable'),evaluation_quantity=(
select ifnull(count(*),0) from evaluation where book_id=b.book_id
and state='enable')
</update>
</mapper>
@Component
public class CaculateTask {
@Resource
private BookService bookService;
@Scheduled(cron="0 * * * * ?")
public void updateEvaluation(){
bookService.updateEvaluation();
}
}
可实现每隔1分钟(xx:xx:00时刻)调用一次book.xml中的sql语句,更新评分和评价数量