项目实战 — 博客系统③ {功能实现}

目录

 一、编写注册功能

🍅 1、使用ajax构造请求(前端)

🍅 2、统一处理

        🎄 统一对象处理

        🎄 保底统一返回处理 

        🎄 统一异常处理

 🍅 3、处理请求

二、编写登录功能

 🍅 1、使用ajax构造请求

🍅 2、处理请求

        🎄 创建实体类

        🎄 添加接口方法

         🎄 service层

        🎄 controller:处理请求并返回

三、编写博客列表页面

 🍅 1、SessionUtils

 🍅 2、处理请求

🍅 3、使用ajax构造请求

三、编写注销功能

🍅 1、使用ajax获取请求

🍅 2、处理请求

四、编写删除文章功能

🍅 1、使用ajax构造请求

🍅 2、处理请求

🎄 mapper层:接口方法

🎄 service层

🎄 controller层:处理请求

五、编写文章添加功能

🍅 1、使用ajax构造请求

🍅 2、处理请求

 🎄mapper层:添加接口方法

 🎄service层:返回受影响行数

🎄 controller:处理添加文章的请求

六、修改功能:查询到修改的文章

🍅 1、通过ajax构造请求

🍅 2、处理请求

🎄Mapper层:添加接口

🎄service层

🎄controller层

七、修改功能:修改查询到的文章

🍅 1、通过ajax构造请求           

🍅 2、处理请求

🎄 mapper层

🎄 service层

🎄 controller层     

八、文章详情

🍅 1、前端页面编写

🎄 给定id值

 🎄 使用ajax构造请求

🍅 2、处理请求

🎄 mapper层

🎄 service层

🎄 controller层 

九、阅读量设置

🍅 处理请求

🎄 mapper层

🎄 service层

🎄 controller层 

 十、分页处理

🍅 1、前端处理

🍅 2、后端处理

🎄 mapper层

🎄 service层

🎄 controller层 

十一、密码加盐

🍅 1、定义加密规则

🍅 2、修改UserController代码


前置知识:

前后端交互的关键:使用AJAX(异步局部提交)

写法:

        1、原生写法(兼容性差)

        2、使用框架,jQuery ajax(简单 / 通用性浩)

语法:

        jQuery.ajax({url:"接口地址",           //提高的接口地址type:"GET",               //请求的类型data:{                         //传递的数据"username":"张三","password":"123"},success:function(res){        //相应的结果是什么//后端返回数据后的业务处理代码}});

 一、编写注册功能

🍅 1、使用ajax构造请求(前端)

在前端页面的<head></head>添加jquery

<script src="js/jquery.min.js"></script>

添加事件:点击提交按钮,触发mysub()

<div class="row"><button id="submit" onclick="mysub()">提交</button>
</div>

在<script></script>中提交用户注册信息

主要有这几步:

        (1)参数效验(获取到数据|非空效验)

        (2)将数据提交给后端

        (3)将后端返回的结果给用户

username.focus():指将光标返回

trim():去空格操作(校验到全是空格)

<script>//  提交用户注册信息function mysub(){// 参数校验var username = jQuery("#username");var password = jQuery("#password");var password2 = jQuery("#password2");if(username.val().trim()==""){alert("请先输入用户名!");username.focus();return false;}if(password.val().trim()==""){alert("请先输入密码!");password.focus();return false;}if(password2.val().trim()==""){alert("请先输入确认密码!");password2.focus();return false;}// 效验两次输入的密码是否一致if(password.val()!=password2.val()){alert("两次密码不一致,请先检查!");return false;}//     提交数据给后端jQuery.ajax({url:"/user/reg",// 查询使用get,非查询使用posttype:"POST",data:{"username":username.val().trim(),"password":password.val().trim()},success:function (res){//     返回结果给用户if (res.code==200 && res.data==1){alert("注册成功!")location.href = "login.html";}else {alert("注册失败!" + res.msg);}}});}</script>
</body>

🍅 2、统一处理

        🎄 统一对象处理

 在common包中,编写ResultAjax,表示前后端交互的统一对象,统一处理

@Data
public class ResultAjax {private int code;   //状态码private String msg; //状态码的描述信息private Object data;public static ResultAjax success(Object data){ResultAjax result = new ResultAjax();result.setCode(200);result.setMsg("");result.setData(data);return result;}public static ResultAjax success(int code,String msg,Object data){ResultAjax result = new ResultAjax();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}public static ResultAjax fail(int code,String msg){ResultAjax result = new ResultAjax();result.setCode(code);result.setMsg(msg);result.setData(null);return result;}public static ResultAjax fail(int code,String msg,Object data){ResultAjax result = new ResultAjax();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}
}

        🎄 保底统一返回处理 

        在common中创建类

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof ResultAjax){return body;}if (body instanceof String){ResultAjax resultAjax = ResultAjax.success(body);try {return objectMapper.writeValueAsString(resultAjax);} catch (JsonProcessingException e) {e.printStackTrace();}}return ResultAjax.success(body);}
}

        🎄 统一异常处理

/*
* 统一异常处理
* */
@RestControllerAdvice
public class ExceptionAdvice {@ExceptionHandler(Exception.class)public ResultAjax doException(Exception e){return ResultAjax.fail(-1,e.getMessage());}
}

 🍅 3、处理请求

 编写Mapper层,将拿到的数据进行插入

@Mapper
public interface UserMapper {@Insert("insert into userinfo(username,password) values (#{username},#{password})")int reg(Userinfo userinfo);
}

然后在Service层中使用@Autowired将userMapper注入

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public int reg(Userinfo userinfo){return userMapper.reg(userinfo);}
}

 在UserController中使用Userinfo对象接收请求信息

        (1)校验参数

        (2)请求 service 进行添加操作

        (3)将执行的结果返回给前端

@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@RequestMapping("/reg")public ResultAjax reg(Userinfo userinfo){if (userinfo == null || !StringUtils.hasLength(userinfo.getUsername())|| !StringUtils.hasLength(userinfo.getPassword())){return ResultAjax.fail(-1,"非法参数");}int result = userService.reg(userinfo);return ResultAjax.success(result);}

检验该功能是否实现

 查看数据库是否插入张三的信息:

二、编写登录功能

 🍅 1、使用ajax构造请求

 在前端页面的<head></head>添加jquery

<script src="js/jquery.min.js"></script>

添加事件:点击提交按钮,触发mysub()

<div class="row"><button id="submit" onclick="doLogin()">提交</button>
</div>

        (1)校验参数

        (2)将数据提交给后端

        (3)将结果展示给前端

<script>function doLogin(){// 参数校验var username = jQuery("#username");var password = jQuery("#password");if(username.val().trim()==""){alert("请先输入用户名!");username.focus();return false;}if(password.val().trim()==""){alert("请先输入密码!");password.focus();return false;}//     将数据提交给后端jQuery.ajax({url:"/user/login",type:"GET",data:{"username":username.val(),"password":password.val()},success:function(res){//     将结果展示给用户if (res.code==200 && res.data==1){alert("登录成功!");location.href="myblog_list.html";}else {alert("登录失败!" + res.msg);}}});}
</script>

🍅 2、处理请求

        🎄 创建实体类

首先,再创建一个扩展Userinfo的实体类,UserinfoVO

/*
* userinfo扩展类
* */
@Data
public class UserinfoVO extends Userinfo {private String checkCode;
}

        🎄 添加接口方法

在UserMapper中添加以下方法:

@Select("select * from userinfo where username = #{username} order by id desc")Userinfo getUserByName(@Param("username")String username);

         🎄 service层

 public Userinfo getUserByName(String username){return userMapper.getUserByName(username);}

        🎄 controller:处理请求并返回

首先创建一个公共类(common包中):AppVariable

设置一个用户的session key

/*
* 全局变量
* */
public class AppVariable {public static final String SESSION_USERINFO_KEY = "SESSION_USERINFO";
}

        (1)参数校验

        (2)根据用户名查询对象

        (3)适用对象中的密码和用户输入的密码进行比较

          登录验证思路:根据用户名查询对象,如果查询到对象,则用查询到的对象和传递过              来的密码对比。如果相同,则说明登陆成功,反之则不能。   

        (4)比较成功之后,将对象存储到session中

        (5)将结果返回给用户

 @RequestMapping("/login")public ResultAjax login(UserinfoVO userinfoVO, HttpServletRequest request){//参数校验if (userinfoVO == null || !StringUtils.hasLength(userinfoVO.getUsername()) ||!StringUtils.hasLength(userinfoVO.getPassword())){
//            是非法登录return ResultAjax.fail(-1,"参数有误!");}//根据用户查询对象Userinfo userinfo = userService.getUserByName(userinfoVO.getUsername());if (userinfo == null || userinfo.getId() == 0){return ResultAjax.fail(-2,"用户名或密码错误!");}//使用对象中的密码和用户输入的密码进行比较if (!userinfoVO.getPassword().equals(userinfo.getPassword())){
//            密码错误return ResultAjax.fail(-2,"用户名或密码错误!");}//比较成功,将对象存储到session中HttpSession session = request.getSession();session.setAttribute(AppVariable.SESSION_USERINFO_KEY,userinfo);//将结果返回给用户return ResultAjax.success(1);}

三、编写博客列表页面

 🍅 1、SessionUtils

由于要拿到用户的信息,也就是拿到用户对象,比如修改和删除博客等功能(都是需要拿到用户),所以得到用户对象就属于一个高频事件。

所以就创建一个类,可以得到用户对象。

/*
* session工具类
* */
public class SessionUtils {
//    得到登录用户public static Userinfo getUser(HttpServletRequest request){
//        false代表有session就创建session,没有就创建HttpSession session = request.getSession(false);if (session != null && session.getAttribute(AppVariable.SESSION_USERINFO_KEY) != null){
//            登录状态return (Userinfo) session.getAttribute(AppVariable.SESSION_USERINFO_KEY);}return null;}
}

 🍅 2、处理请求

🎄 添加接口方法(mapper)

@Mapper
public interface ArticleMapper {@Select("select * from articleinfo where uid=#{uid}")List<ArticleMapper> getListByUid(@Param("uid")int uid);
}

🎄 service层

对象注入

@Service
public class ArticleService {@Autowiredprivate ArticleMapper articleMapper;public List<ArticleMapper> getListByUid(int uid){return articleMapper.getListByUid(uid);}
}

🎄controller处理请求并返回响应

使用并行的方式处理文章正文(_DESC_LENGTH是简介)

@RestController
@RequestMapping("art")
public class ArticleController {@Autowiredpublic ArticleService articleService;private static final int _DESC_LENGTH = 120;@RequestMapping("/mylist")public ResultAjax myList(HttpServletRequest request){
//        得到登录用户Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-1,"请先登录");}
//      根据用户id查询用户发表的文章List<Articleinfo> list = articleService.getListByUid(userinfo.getId());
//        处理list -> 将文章正文变成简介if (list != null && list.size() > 0){
//            并行处理list集合list.stream().parallel().forEach((art)->{if (art.getContent().length() > _DESC_LENGTH){art.setContent(art.getContent().substring(0,_DESC_LENGTH));}});}
//        返回前端return ResultAjax.success(list);}
}

🍅 3、使用ajax构造请求

在前端页面的<head></head>添加jquery

<script src="js/jquery.min.js"></script>

添加一个id,包含了文章列表的div

       <div id="artListDiv" class="container-right">
 <script>// 初始化方法function init(){jQuery.ajax({url:"/art/mylist",type:"GET",data:{},success:function(res){if(res.code==200){// 请求成功var createHtml = "";var artList = res.data;if(artList==null || artList.length==0){// 未发表文章createHtml += "<h3 style='margin-left:20px;margin-top:20px'>暂无文章,请先"+"<a href='blog_add.html'>添加</a>!</h3>";}else{for(var i=0;i<artList.length;i++){var art = artList[i];createHtml += '<div class="blog">';createHtml += '<div class="title">'+art.title+'</div>';createHtml += '<div class="date">'+art.createtime+'</div>';createHtml += '<div class="desc">';createHtml += art.content;createHtml += '</div>';createHtml += ' <a href="blog_content.html?aid='+art.id + '" class="detail">查看全文 &gt;&gt;</a>&nbsp;&nbsp;';createHtml += '<a href="blog_edit.html?aid='+art.id + '" class="detail">修改 &gt;&gt;</a>&nbsp;&nbsp;';createHtml += ' <a href="javascript:del('+art.id+')" class="detail">删除 &gt;&gt;</a>';createHtml += '</div>';}}jQuery("#artListDiv").html(createHtml);}else{alert("抱歉:操作失败!"+res.msg);}}});}init();</script>
</body>

三、编写注销功能

🍅 1、使用ajax获取请求

由于注销功能,在很多页面都需要用到,所以这里就给一个公共的js

function logout(){if (confirm("是否确定注销?")){// 1、在后端删除session信息jQuery.ajax({url:"/user/logout",type:"POST",data:{},success:function (res){}});// 2、跳转到登录页location.href = "login.html"}
}

 进入到myblog_list.html中:

<script src="js/logout.js"></script>
<a href="javascript:logout()">注销</a>

🍅 2、处理请求

//注销@RequestMapping("/logout")public ResultAjax logout(HttpServletRequest request){HttpSession session = request.getSession(false);if (session!=null &&session.getAttribute(AppVariable.SESSION_USERINFO_KEY)!=null){session.removeAttribute(AppVariable.SESSION_USERINFO_KEY);}return ResultAjax.success(1);}

四、编写删除文章功能

🍅 1、使用ajax构造请求

在myblog_list.html中添加对应的js代码

主要是根据id删除文章:

        1、校验参数

        2、将数据返回给后端进行删除操作

        2、将结果展示给用户

 //     删除文章操作(根据id删除)function del(aid){//     参数校验if(aid=="" || aid<=0){alert("参数错误");return false;}//     将数据返回给后端进行删除操作jQuery.ajax({url:"/art/del",type:"POST",data:{"aid":aid},success:function (res){//     将结果展示给用户if (res.code==200 && res.data==1){alert("恭喜:删除成功!");//     刷新页面location.href = location.href;}else {//     删除失败alert("抱歉:操作失败!"+res.msg);}}});}

🍅 2、处理请求

🎄 mapper层:接口方法

在ArticleMapper中添加接口方法

@Delete("delete from articleinfo where id=#{aid} and uid=#{uid}")
int del(@Param("aid")Integer aid,int uid);

🎄 service层

public int del(Integer aid,int uid){return articleMapper.del(aid,uid);}

🎄 controller层:处理请求

主要有以下几步:

        1、参数校验

        2、得到当前登录的用户

        3、判断文章的归属人并且进行删除操作

        4、将结果返回给前端

//    删除文章@RequestMapping("/del")public ResultAjax del(Integer aid,HttpServletRequest request){if (aid==null || aid<=0){return ResultAjax.fail(-1,"参数错误!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-1,"请先登录!");}int result = articleService.del(aid,userinfo.getId());return ResultAjax.success(result);}

五、编写文章添加功能

🍅 1、使用ajax构造请求

        (1)非空校验

        (2)将用户提交的数据传递给后端

        (3)将后端返回的结果展示给用户

进入到blog_add.html中,添加如下代码

 function mysub(){var title = jQuery("#title");if (title.val.trim()==""){alert("请先输入标题!");title.focus();return false;}if (editor.getValue()==""){alert("请先输入正文!");return false;}jQuery.ajax({url:"/art/add",type:"POST",data:{"title":title.val(),"content":editor.getValue()},success:function (res){// 文章添加成功if (res.code==200 && res.data==1){if (confirm("恭喜:添加成功!是否继续添加文章?")){location.href=location.href;}else{location.href="myblog_list.html"}}else {//文章添加失败alert("抱歉:操作失败!"+res.msg);}}});}

🍅 2、处理请求

 🎄mapper层:添加接口方法

@Insert("insert into articleinfo(title,content,uid) values(#{title},#{content},#{uid})")int add(Articleinfo articleinfo);

 🎄service层:返回受影响行数

public int add(Articleinfo articleinfo){return articleMapper.add(articleinfo);}

🎄 controller:处理添加文章的请求

主要分为以下几步:

        (1)校验参数

        (2)组装数据

        (3)将数据入库

        (4)将结果返回给前端

@RequestMapping("/add")public ResultAjax add(Articleinfo articleinfo,HttpServletRequest request){if (articleinfo==null || !StringUtils.hasLength(articleinfo.getTitle())|| !StringUtils.hasLength(articleinfo.getContent())){return ResultAjax.fail(-1,"非法参数!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-2,"请先登录");}articleinfo.setUid(userinfo.getId());int result = articleService.add(articleinfo);return ResultAjax.success(result);}

六、修改功能:查询到修改的文章

🍅 1、通过ajax构造请求

(1)获取url中的参数:

(例如)localhost:8080/blog_edit.html?aid=2&uid=1

        a、通过location.search获取“?”后面的参数

        b、去除“?”

        c、根据“&”将参数分割成多个数组

        d、循环对比key,并返回查询value

创建一个公共的js:

// 根据key获取到对应的url中对应的value
function getParamValue(key){var params = location.search;if (params.indexOf("?")>=0){params=params.substring(1);var paramArray=params.split("&");if (paramArray.length>=1){for (var i = 0; i < paramArray.length; i++) {var item=paramArray[i].split("=");if (item[0]==key[1]){return item;}}}}return null;
}

(2)校验 aid

(3)查询文章详情

(4)将文章的详情信息展示到页面

首先在head中添加得到参数的方法

    <script src="js/urlutils.js"></script>

在blog_edit.html中的<script></script>中添加代码

        var aid=getParamValue("aid");function init(){if (aid==null || aid<=0){alert("非法参数")return false;}jQuert.ajax({url:"/art/getdetail",type:"GET",data:{"aid":aid},success:function(res){if (res.code==200 && res.data!=null && res.data.id>0){jQuery("#title").val(res.data.title);initEdit(res.data.content);}else {alert("抱歉,查询失败!"+res.msg);}}});}init();

🍅 2、处理请求

🎄Mapper层:添加接口

进入到ArticleMapper中

@Select("select  * from aeticleinfo where id=#{aid} and uid=#{uid}")Articleinfo getArticleByIdAndUid(@Param("aid")int aid,@Param("uid")int uid);

🎄service层

 public Articleinfo getArticleByIdAndUid(int aid,int uid){return ArticleMapper.getArticleByIdAndUid(aid,uid);}

🎄controller层

(1)校验参数

(2)得到当前登录用户id

(3)查询文章并且校验权限

@RequestMapping("/update_init")public ResultAjax updateInit(Integer aid,HttpServletRequest request){if (aid==null || aid<=0 ){return ResultAjax.fail(-1,"参数有误!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-2,"请先登录!");}Articleinfo articleinfo = articleService.getArticleByIdAndUid(aid,userinfo.getId())return ResultAjax.success(articleinfo);}

七、修改功能:修改查询到的文章

🍅 1、通过ajax构造请求           

进入到blog_edit.html中     

        <button onclick="doUpdate()">修改文章</button>
function doUpdate(){if(title.val().trim()==""){alert("请先输入标题!");title.focus();return false;}if(editor.getValue()==""){alert("请先输入正文!");return false;}jQuery.ajax({url:"/art/update",type:"POST",data:{"id":aid,"title":title.val(),"content":editor.getValue()},success:function(res){if(res.code==200 && res.data==1){// 修改成功alert("恭喜:修改成功!");// 跳转到我的文章管理员location.href = "myblog_list.html";}else if(res.code==-2){alert("请先的登录!");location.href = "login.html";}else{alert("抱歉:修改失败!"+res.msg);}}});}

🍅 2、处理请求

🎄 mapper层

进入到ArticleMappe中

@Update("update articleinfo set title=#{title},content=#{content} where id=#{id} and uid=#{uid}")int update(Articleinfo articleinfo);

🎄 service层

进入到ArticleService中

public int update(Articleinfo articleinfo){return articleMapper.update(articleinfo);}

🎄 controller层     

(1)参数校验

(2)获取登录用户

(3)修改文章,并且校验归属人

(4)返回结果

//    修改文章信息@RequestMapping("/update")public ResultAjax update(Articleinfo articleinfo,HttpServletRequest request){if (articleinfo==null || !StringUtils.hasLength(articleinfo.getTitle())|| !StringUtils.hasLength(articleinfo.getContent())|| articleinfo.getId() == 0){return ResultAjax.fail(-1,"非法参数!");}Userinfo userinfo = SessionUtils.getUser(request);if (userinfo == null){return ResultAjax.fail(-2,"请先登录!");}articleinfo.setUid(userinfo.getId());int result = articleService.update(articleinfo);return ResultAjax.success(result);}

八、文章详情

🍅 1、前端页面编写

进入到blog_content.html中

🎄 给定id值

    //左侧的个人信息<img id="photo" src="img/avatar.png" class="avtar" alt=""><h3 id="username"></h3><a href="http:www.github.com">github 地址</a>
        //右侧的博客信息<!-- 博客标题 --><h3 id="title"></h3><!-- 博客时间 --><div class="date">发布时间:<span id="createtime"></span>/阅读量:<span id="rcount"></span></div>

 🎄 使用ajax构造请求

        var aid = getParamValue("aid");
//初始化页面function init(){var aid = getParamValue("aid");if (aid==null || aid<=0){alert("参数有误!");return false;}jQuery.ajax({url:"/art/detail",type:"GET",data:{"aid":aid},success: function (res){if (res.code==200 && res.data!=null){var user = res.data.user;var art = res.data.art;if (user!=null){if(user.photo!=""){jQuery("#photo").art("src,user.photo");}jQuery("#username").html(user.username);jQuery("#artcount").html(user.artCount);}else{alert("抱歉:查询失败!"+reg.msg);}if(art!=null){jQuery("#title").html(art.title);jQuery("#createtime").html(art.createtime);jQuery("#rcount").html(art.rcount);initEdit(art.content);}else{alert("抱歉:查询失败!"+reg.msg)}}else{alert("抱歉,查询失败!"+res.msg);}}});}

🍅 2、处理请求

首先在userinfoVO中添加一个变量:

    private int artCount;   //用户发布的文章总数

🎄 mapper层

首先在Articleinfo中添加一条sql:根据id查询文章

@Select("select * from articleinfo where id=#{aid}")Articleinfo getDetaiById(@Param("aid") int aid);@Select("select count(*) from articleinfo where uid=#{uid}")int getArticleByUid(@Param("uid")int uid);

 然后再Userinfo中添加一条sql:根据id查询用户

@Select("select * from us erinfo where id=#{uid}")UserinfoVO getUserById(@Param("uid") int uid);

🎄 service层

ArticleService中

    public Articleinfo getDetail(int aid){return articleMapper.getDetaiById(aid);}public int getArtCountByUid(int uid){return articleMapper.getArticleByUid(uid);}

 UserService中

    public UserinfoVO getUserById(int uid){return userMapper.getUserById(uid);}

🎄 controller层 

(1)参数校验

(2)查询文章详情 

(3)根据uid查询用户的详情

(4)根据uid查询用户发表的总文章数

(5)组装数据

(6)返回结果给前端

首先创建一个线程池

使用ThreadPoolExecutor来构造线程池,该方法其实和JDK中的ThreadPool区别就在于,ThreadPoolExecutor式通过参数的方式去设置,而ThreadPool是通过构造方法,ThreadPoolExecutor中的方式更加直观简单。

ThreadPool然后将其注入依赖

    @Autowiredprivate ThreadPoolTaskExecutor taskExecutor;

 处理请求:

先注入依赖:

    @Autowiredprivate UserService userService;

 使用多线程并发编程就可以很快的查询到对应的文章详情了。

//查询文章详情页@RequestMapping("/detail")public ResultAjax detail(Integer aid) throws ExecutionException, InterruptedException {if(aid==null || aid<=0){return ResultAjax.fail(-1,"非法参数");}Articleinfo articleinfo = articleService.getDetail(aid);if (articleinfo == null || articleinfo.getId() <= 0){return ResultAjax.fail(-1,"非法参数!");}//根据uid查询用户的详情FutureTask<UserinfoVO> userTask = new FutureTask(()->{return userService.getUserById(articleinfo.getUid());});taskExecutor.submit(userTask);//根据uid查询用户发表的文章数FutureTask<Integer> artCountTask = new FutureTask<>(()->{return articleService.getArtCountByUid(articleinfo.getUid());});taskExecutor.submit(artCountTask);//等待任务(线程池)执行完UserinfoVO userinfoVO = userTask.get();int artCount = artCountTask.get();userinfoVO.setArtCount(artCount);//数据组装HashMap<String,Object> result = new HashMap<>();result.put("user",userinfoVO);result.put("art",articleinfo);return ResultAjax.success(result);}

九、阅读量设置

🍅 使用ajax构造请求

 //访问量+1function increamentRCount(){if (aid==null || aid<=0 ){return false;}jQuery.ajax({url:"/art/increment_rcount",type:"POST",data:{"aid":aid},success:function(res){}});}increamentRCount();

🍅 处理请求

🎄 mapper层

    @Update("update articleinfo set rcount=rcount+1 where id=#{aid}")int incrementRCount(@Param("aid") int aid);

🎄 service层

    public int incrementRCount(int aid){return articleMapper.incrementRCount(aid);}

🎄 controller层 

(1)校验参数

(2)更改数据库

(3)返回结果

 @RequestMapping("/increment_rcount")public ResultAjax incrementRCount(Integer aid){if (aid==null || aid<=0){return ResultAjax.fail(-1,"参数有误!");}int result = articleService.incrementRCount(aid);return ResultAjax.success(result);}

 十、分页处理

核心参数:

        (1)页码(当前在第几页)

        (2)每页显示的最大条数(前端灵活的控制分页功能)

后端分页返回:

        (1)当前页面的文章列表

        (2)总共有多少页:根据博客总条数/每一页显示条数的结果,向上取整(比如3.3333             取为4)

🍅 1、前端处理

首先将对应的js引入进,来根据总条数每页显示条数(向上取整

添加一个id属性:主要是为了构造出每一条博客的div出来

<!-- 每一篇博客包含标题, 摘要, 时间 -->    <div id="artListDiv"></div>

 然后初始化数据:

        (1)得到url中的分页参数

        (2)qing求后端接口

        (3)将结果返回给用户

var psize = 2; // 每页显示条数var pindex = 1; // 页码var totalpage = 1; // 总共有多少页// 初始化数据function init(){// 1.处理分页参数psize = getParamValue("psize");if(psize==null){psize = 2; // 每页显示条数}pindex = getParamValue("pindex");if(pindex==null){pindex = 1; // 页码}jQuery("#pindex").html(pindex);// 2.请求后端接口jQuery.ajax({url:"/art/getlistbypage",type:"GET",data:{"pindex":pindex,"psize":psize},success:function(res){// 3.将结果展示给用户if(res.code==200 && res.data!=null){var createHtml = "";if(res.data.list!=null && res.data.list.length>0){// 有文章totalpage = res.data.size;jQuery("#pszie").html(totalpage);var artlist = res.data.list;for(var i=0;i<artlist.length;i++){var art = artlist[i]; // 文章对象createHtml += '<div class="blog" >';createHtml += '<div class="title">'+art.title+'</div>';createHtml += '<div class="date">'+art.createtime+'</div>';createHtml += '<div class="desc">'+art.content+'</div>';createHtml += '<a href="blog_content.html?aid='+art.id+'" class="detail">查看全文 &gt;&gt;</a>';createHtml += '</div>';}}else{// 暂无文章createHtml += '<h3 style="margin-top:20px;margin-left:20px;">暂无文章!</h3>';}jQuery("#artListDiv").html(createHtml);}else{alert("抱歉:查询失败!"+res.msg);}}});}init();//点击首页function doFirst(){if (pindex<=1){alert("已经在首页了,无需跳转");return false;}location.href = "blog_list.html";}//跳转到末页function doLast(){if (pindex>=totalpage){alert("已经在末页了,无需跳转!");return false;}location.href="blog_list.html?pindex="+totalpage;}//点击上一页function doBefore(){if (pindex<=1){alert("已经在首页了,无需跳转");return false;}location.href="blog_list.html?pindex="+(parseInt(pindex)-1);}//点击下一页function doNext(){if (pindex>=totalpage){alert("已经在末页了,无需跳转!");return false;}location.href="blog_list.html?pindex="+(parseInt(pindex)+1);}

🍅 2、后端处理

推导到分页公式:每页显示两条数据

每次只有偏移量offset变了

# 第一页
mysql> select * from articleinfo order by id limit 2 offset 0;# 第三页
mysql> select * from articleinfo order by id limit 2 offset 2;# 第四页
mysql> select * from articleinfo order by id limit 2 offset 2;
.....

假设每条显示条数为pageSize,页码为pageIndex

故而推到出的公式为:offset = pageSize*(pageIndex-1)

🎄 mapper层

    @Select("select * from articleinfo order by id desc limit #{psize} offset #{offset} ")public List<Articleinfo> getListByPage(@Param("psize") int psize,@Param("offset")int offset);@Select("select count(*) from articleinfo")int getCount();

🎄 service层

   public List<Articleinfo> getListByPage(int psize,int offset){return articleMapper.getListByPage(psize, offset);}

🎄 controller层 

        (1)加工矫正

        (2)并发进行文章列表和总页数的查询

        (3)组装数据

        (4)将结果返回给前端

   @RequestMapping("/getlistbypage")public ResultAjax getListByPage(Integer pindex,Integer psize) throws ExecutionException, InterruptedException {if (pindex == null || pindex < 1){pindex = 1;}if (psize==null || psize<1){psize = 2;}//查询分页列表数据:Integer finalPsize = psize;Integer finalPindex = pindex;FutureTask<List<Articleinfo>> listTask = new FutureTask<>(()->{int finalOffset = finalPsize *(finalPindex -1);return articleService.getListByPage(finalPsize,finalOffset);}) ;//查询总页数FutureTask<Integer> sizeTask = new FutureTask<>(()->{int totalCount = articleService.getCount();double sizeTemp = (totalCount * 1.0) / (finalPsize * 1.0);return (int) Math.ceil(sizeTemp);});taskExecutor.submit(listTask);taskExecutor.submit(sizeTask);List<Articleinfo> list = listTask.get();int size = sizeTask.get();HashMap<String,Object> map = new HashMap<>();map.put("list",list);map.put("size",size);return ResultAjax.success(map);}

十一、密码加盐

先修改数据库中的字段:

mysql> alter table userinfo modify password varchar(65) not null;

🍅 1、定义加密规则

加密流程: 

使用加盐算法,也就是使用一个不重复随机的盐值+密码,得到一个无规律的密码                 (1)生成一个盐值

(2)(根据盐值 + 固定密码)进行加密 -> md5(盐值 + 密码)= 最终密码

(3)将[盐值]+ [分隔符$] + 最终密码保存到数据库中 

验证密码流程:

(1)得到盐值

(2)md5(盐值+待验证密码)->  最终待验证的密码

(3)对比最终待验证的密码和数据中的最终密码是否相同-> 相同密码正确

        

创建一个加密解密的类:                                  

 

 

public class PasswordUtils {//加盐加密public static String encrypt(String password){String salt = UUID.randomUUID().toString().replace("-","");String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));return salt+"$"+finalPassword;}//待验证密码public static boolean decrypt(String password,String dbPassword){if (!StringUtils.hasLength(password) || !StringUtils.hasLength(dbPassword) ||dbPassword.length() != 65){return false;}String[] dbPasswordArray = dbPassword.split("$");if (dbPasswordArray.length!=2){return false;}String salt = dbPasswordArray[0];String dbFinalPassword = dbPasswordArray[1];String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));if (finalPassword.equals(dbFinalPassword)){return true;}return false;}
}

🍅 2、修改UserController代码

reg()方法中添加以下代码:

        userinfo.setPassword(PasswordUtils.encrypt(userinfo.getPassword()));

 在login()方法中添加以下代码

//使用对象中的密码和用户输入的密码进行比较if (!PasswordUtils.decrypt(userinfoVO.getPassword(),userinfo.getPassword())){return ResultAjax.fail(-2,"用户名或者密码错误!");}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/46168.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue引入 import { decode } from ‘js-base64‘

vue引入 import { decode } from ‘js-base64’ package.json 里面加上 需要用的地方 加上 import { decode } from ‘js-base64’ let params decode(loook)最后 npm install

sh 脚本循环语句和正则表达式

目录 1、循环语句 1、for 2、while 3、until 2、正则表达式 1、元字符 2、表示次数 3、位置锚定 4、分组 5、扩展正则表达式 1、循环语句 循环含义 将某代码段重复运行多次&#xff0c;通常有进入循环的条件和退出循环的条件 重复运行次数 循环次数事先已知 循环次…

爱荷华州的一个学区正在使用ChatGPT来决定禁止哪些书籍

为了响应爱荷华州最近颁布的立法&#xff0c;管理员们正在从梅森市学校图书馆移除禁书&#xff0c;官员们正在使用ChatGPT帮助他们挑选书籍&#xff0c;根据公报和大众科学. 由州长金雷诺兹签署的禁令背后的新法律是教育改革浪潮的一部分&#xff0c;共和党立法者认为这是保护…

OLED透明屏案例:揭示技术创新的无限可能性

OLED透明屏作为一项创新性技术&#xff0c;在各个领域展现出了令人惊叹的应用潜力。 那么&#xff0c;尼伽便通过介绍一些具体的OLED透明屏案例&#xff0c;探索其在智能家居、汽车行业、商业展示、航空航天、教育与培训以及医疗健康等领域的成功应用。 这些案例将展示OLED透明…

下线40万辆,欧拉汽车推出2023款好猫尊荣型和GT木兰版

欧拉汽车是中国新能源汽车制造商&#xff0c;成立于2018年。截至目前&#xff0c;已经下线了40万辆整车&#xff0c;可见其在市场的影响力和生产实力。为了庆祝这一里程碑&#xff0c;欧拉汽车推出了品牌书《欧拉将爱进行到底》&#xff0c;在其中讲述了欧拉汽车的发展历程和未…

ORB-SLAM2学习笔记9之图像帧Frame

先占坑&#xff0c;明天再完善… 文章目录 0 引言1 Frame类1.1 成员函数1.2 成员变量 2 Frame类的用途 0 引言 ORB-SLAM2学习笔记8详细了解了图像特征点提取和描述子的生成&#xff0c;本文在此基础上&#xff0c;继续学习ORB-SLAM2中的图像帧&#xff0c;也就是Frame类&#…

VBA技术资料MF44:VBA_把数据从剪贴板粘贴到Excel

【分享成果&#xff0c;随喜正能量】人皆知以食愈饥&#xff0c;莫知以学愈愚,生命中所有的不期而遇都是你努力的惊喜.人越纯粹&#xff0c;就越能感受到美。大江、大河、大海、大山、大自然&#xff0c;这些风景从来都不会受“属于谁”的污染&#xff0c;人人都感受到它们的美…

搭建Everything+cpolar在线资料库,实现随时随地访问

Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问 文章目录 Everythingcpolar搭建在线资料库&#xff0c;实现随时随地访问前言1.软件安装完成后&#xff0c;打开Everything2.登录cpolar官网 设置空白数据隧道3.将空白数据隧道与本地Everything软件结合起来总结 前…

MySQL索引常见术语(索引下推、索引覆盖、最左匹配等)

一:背景 我们在面试中都知道,对于MySQL索引是必问的。大家也应该都知道MySQL的数据结构,什么是索引。其中在面试中,面试官也经常问,你做过哪些优化?本文主要是介绍MySQL索引的一些常见术语,比如索引下推、索引覆盖、最左匹配等,这些其实也是MySQL优化的一部分,能够熟练…

Docker修改daemon.json添加日志后无法启动的问题

docker实战(一):centos7 yum安装docker docker实战(二):基础命令篇 docker实战(三):docker网络模式(超详细) docker实战(四):docker架构原理 docker实战(五):docker镜像及仓库配置 docker实战(六):docker 网络及数据卷设置 docker实战(七):docker 性质及版本选择 认知升…

了解 JSON 格式

一、JSON 基础 JSON&#xff08;JavaScript Object Notation&#xff0c;JavaScript 对象表示法&#xff09;是一种轻量级的数据交换格式&#xff0c;JSON 的设计目的是使得数据的存储和交换变得简单。 JSON 易于人的阅读和书写&#xff0c;同时也易于机器的解析和生成。尽管 J…

Go语言基础之基本数据类型

Go语言中有丰富的数据类型&#xff0c;除了基本的整型、浮点型、布尔型、字符串外&#xff0c;还有数组、切片、结构体、函数、map、通道&#xff08;channel&#xff09;等。Go 语言的基本类型和其他语言大同小异。 基本数据类型 整型 整型分为以下两个大类&#xff1a; 按…

聚焦电力行业CentOS迁移,麒麟信安受邀参加第六届电力信息通信新技术大会暨数字化发展论坛并发表主题演讲

为加快推进“双碳”目标下的新型能源体系和新型电力系统建设&#xff0c;深化新一代数字技术与电力业务的融合发展&#xff0c;促进电力行业关键技术自主创新、安全可控&#xff0c;助力电力企业数字化转型升级和高质量发展&#xff0c;2023年8月9-11日&#xff0c;第六届电力信…

实现el-table两列多选框且不可同时勾选

1、效果图如下&#xff0c;功能&#xff1a;必修和选修不可同时勾选 2、代码如下 <template><el-table :data"addTableData" style"width: 100%"><el-table-column label"必修" width"55px" align"center"…

AIGC音视频工具分析和未来创新机会思考

编者按&#xff1a;相较于前两年&#xff0c;2023年音视频行业的使用量增长缓慢&#xff0c;整个音视频行业遇到瓶颈。音视频的行业从业者面临着相互竞争、不得不“卷”的状态。我们需要进行怎样的创新&#xff0c;才能从这种“卷”的状态中脱离出来&#xff1f;LiveVideoStack…

AndroidAGP8.1.0和JDK 17迁移之旅

AndroidAGP8.1.0和JDK 17迁移之旅 前言&#xff1a; 由于我最近写demo的直接把之前的项目从AGP4.2.2升级到8.1.0引发了一些列问题&#xff0c;这里记录一下&#xff0c;前面讲解过迁移DSL方式遇到的问题&#xff0c;这次升级8.1.0也比之前顺利多了&#xff0c;想看DSL迁移的可…

交互消息式IMessage扩展开发记录

IMessage扩展简介 iOS10新加入的基于iMessage的应用扩展&#xff0c;可以丰富发送消息的内容。&#xff08;分享表情、图片、文字、视频、动态消息&#xff1b;一起完成任务或游戏。&#xff09; 简单的将发送的数据内型分为三种&#xff1a; 1.贴纸Stickers&#xff1b; 2.交…

动态内存管理详解

动态内存管理 1.前言 目前来回顾一下想要在内存中开辟空间有哪些方法&#xff1f; 创建变量&#xff1a; int a 0;//在栈上开辟了4字节的空间创建数组&#xff1a; int arr[10] { 0 };//在栈上开辟40字节的空间 但是这两种开辟方式都有两个特点&#xff1a; 开辟的内存空间…

安装搭建私有仓库 Harbor

目录 一. 准备环境 1.1安装 Docker 1.2安装 Docker Compose 二. 下载 Harbor 安装包 三. 解压安装包 四. 配置 Harbor 五. 安装 Harbor 六. 访问 Harbor 七. 创建项目、用户和角色 一. 准备环境 确保您的服务器满足 Harbor 的系统要求。最低要求是至少 2 核 CPU、4GB…

Azure应用程序网关

文章目录 什么是应用程序网关实战演练创建虚拟网络创建虚拟机创建应用程序网关测试搭建结果 什么是应用程序网关 Azure应用程序网关是一种托管服务&#xff0c;用于提供安全、可缩放的 Web 应用程序前端点的应用程序传送控制和保护。它可以通过 SSL 终止、cookie 基于会话持久…