• 知识点7--SSM项目首页功能优化


    继CMS-Demo的1.0版本完成之后,我们要进入完善阶段,必进只是完成了基本功能,不影响运行而已。本篇开始将1.0优化成为2.0版本,同时在优化中我们重点是要加入ES、Redis等数据技术支持。

    首先对于一个CMS来说它的首页一定是重点被查询页面,所以我们优化的第一个点就是首页的响应速度,我们现在可以看一下首页查询用时。
    在这里插入图片描述
    我们可以看到,现在后台查询分页每页6篇,也不多,但是却用了1.5秒,这个速度,我们是无法忍受的,现在而且现在还是本地运行,我们直接开发时访问,假设http://localhost:8080/index.do这个路径正式使用上线了,大量的查询在加上网络的延迟,那我们就一首凉凉送给自己了,我们先优化第一次,使用多线程执行这个任务。

    /**
     *
     * @Title: index
     * @Description: 进入首页
     * @return
     * @return: String
     */
    @RequestMapping("index.do")
    public String index(Model model,Article article,@RequestParam(defaultValue="1")Integer pageNum) {
    	//封装查询条件
    	model.addAttribute("article", article);
    
    	//使用线程
    	Thread t1;
    	Thread t2;
    	Thread t3;
    	Thread t4;
    	//查询所有的栏目,该线程为必须品
    	t1=new Thread(new Runnable() {
    		@Override
    		public void run() {
    			List<Channel> channels = channelService.selects();
    			model.addAttribute("channels", channels);
    		}
    	});
    
    	// 判断栏目ID 不为空 也就是说当前不是查询热点那么就要查询其下分类
    	t2=new Thread(new Runnable() {
    
    		@Override
    		public void run() {
    
    			if(article.getChannelId()!=null){
    				List<Category> categorys = channelService.selectsByChannelId(article.getChannelId());
    				model.addAttribute("categorys", categorys);
    			}else{
    				//如果栏目id是空的那么就代表这查询的是热点,并为为热点查询广告
    				List<Slide> slides = slideService.getAll();
    				model.addAttribute("slides", slides);
    				//限制查询热点文章
    				article.setHot(1);
    			}
    		}
    	});
    
    	//前两个线程决定查什么文章,第三个线程正式查文章
    	t3=new Thread(new Runnable() {
    
    		@Override
    		public void run() {
    			try {
    				t2.join();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			//无论是什么情况控制查询文章不是被逻辑删除的
    			article.setDeleted(0);
    			//不能查询非审核之后的文章
    			article.setStatus(1);
    			//查询符合条件的所有文章
    			List<Article> selectArticle = articleService.selectArticle(article, pageNum, 6);
    			PageInfo info=new PageInfo<>(selectArticle);
    			model.addAttribute("info", info);
    		}
    
    	});
    
    	//为首页查询五条最新的文章
    	t4=new Thread(new Runnable() {
    
    		@Override
    		public void run() {
    
    			//	封装该查询条件
    			Article latest = new Article();
    			latest.setDeleted(0);
    			//不能查询非审核之后的文章
    			latest.setStatus(1);
    			List<Article> newArticles = articleService.selectArticle(latest, 1, 5);
    			PageInfo lastArticles=new PageInfo<>(newArticles);
    			model.addAttribute("lastArticles", lastArticles);
    		}
    	});
    
    	//启动线程并保证线程顺序
    	t1.start();
    	t2.start();
    	t3.start();
    	t4.start();
    	try {
    		t1.join();
    		t3.join();
    		t4.join();
    	} catch (InterruptedException e) {
    		e.printStackTrace();
    	}
    	
    	return "index/index";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    我们将首页的Controller使用线程分为四个任务一起跑,现在再执行项目看一下任务需要多少秒。
    在这里插入图片描述
    现在我们可以看到,总耗时不到25毫秒,没有优化前,单一个相应就1.5秒,暂时首页的展示请求响应速度比较满意,先暂时这样。


    第二点优化是首页点击详情的时候,只展示一个详情,太单调了,我们在详情页面中搞一个收藏和评论,但是在开发之前,我们要想一个问题,针对与用户的行为,如果他没有登录我们可以做吗?所以我们需要先开发一个登录拦截器

    package com.wy.interceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    /**
     * 
     * @ClassName: MyInterceptor 
     * @Description: 个人中心拦截器
     * @author: charles
     * @date: 2020年4月10日 上午9:56:23
     */
    public class MyInterceptor extends HandlerInterceptorAdapter {
    	
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		
    	     //不拦截规则--- 如果用户已经登录则不拦截 false:如果有session 则返回session.如果没有则返回null
    		HttpSession session = request.getSession(false);
    		if(session!=null) {//如果存在session 
    			Object user = session.getAttribute("user");//则从session获取登录的user对象
    			if(user!=null)//如果对象不为空
    			 return true;//放行
    		}
    		//没有登录,跳转到登录页面
    		request.setAttribute("msg", "请登录后再试");
    		request.getRequestDispatcher("/WEB-INF/view/passport/login.jsp").forward(request, response);
    		
    		return false;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    但是一个就够了吗?如果后续大家对项目有自己的扩展,总不可能在一个拦截器里写一堆if来判断登录角色吧?所以我们还需要一个管理员的拦截器

    package com.wy.interceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    /**
     * 
     * @ClassName: MyInterceptor 
     * @Description: 管理员拦截器
     * @author: charles
     * @date: 2020年4月10日 上午9:56:23
     */
    public class AdminInterceptor extends HandlerInterceptorAdapter {
    	
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		
    	     //不拦截规则--- 如果用户已经登录则不拦截 false:如果有session 则返回session.如果没有则返回null
    		HttpSession session = request.getSession(false);
    		if(session!=null) {//如果存在session 
    			Object user = session.getAttribute("admin");//则从session获取登录的user对象
    			if(user!=null)//如果对象不为空
    			 return true;//放行
    		}
    		//没有登录,跳转到登录页面
    		request.setAttribute("msg", "请登录后再试");
    		request.getRequestDispatcher("/WEB-INF/view/passport/login_admin.jsp").forward(request, response);
    		return false;
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    随后在springmvc的配置文件中注册这两拦截器

    
    <mvc:interceptors>
        
        <mvc:interceptor>
            
            <mvc:mapping path="/my/**" />
            
            <mvc:exclude-mapping path="/resource/**" />
            
            <bean class="com.wy.interceptor.MyInterceptor" />
        mvc:interceptor>
    
        
        <mvc:interceptor>
            
            <mvc:mapping path="/admin/**" />
            
            <mvc:exclude-mapping path="/resource/**" />
            
            <bean class="com.wy.interceptor.AdminInterceptor" />
        mvc:interceptor>
    mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    现在我们可以运行一下项目,会发现个人中心、管理员两个模块均需要登录,不过这里存在一个功能盲点,就是这个方式跳转的登录由于不是load方式因此长度参照物成了整个浏览器,导致文本框被拉的很长,大家可以自己扩展一下,提供两种思路,一是开发一个新的用于登录的页面,二是使用文档函数把配合js判断当前页面的状态并控制长度,效果可以参考github官网登录那样
    在这里插入图片描述


    现在我们就可以做下一步了,首先在首页的详情页面添加收藏用的按钮以及评论的展示

    
    <div align="right">
    	<c:if test="${isCollect==0 || isCollect==null}">
    		<a href="javascript:collect()">☆ 收藏a>
    	c:if>
    	<c:if test="${isCollect==1}">
    		<span class="text-danger">★ 已收藏span>
    	c:if>
    div>
    
    <c:if test="${null!=sessionScope.user}">
    	<div>
    		输入评论:
    		<textarea rows="8" cols="110" name="content">textarea>
    		<br>
    		<button class="btn btn-info" onclick="addComment()">提交评论button>
    	div>
    c:if>
    
    <div>
    	<c:forEach items="${info.list}" var="comment">
       ${comment.user.username }  <fmt:formatDate
    			value="${comment.created}" pattern="yyyy-MM-dd HH:mm:ss" />
    		<br>
    		<p class="mt-3">${comment.content }p>
    		<hr>
    	c:forEach>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    此时我们就需要先该改一下,详情页跳转的Controller,我们要查询出当前文章是否被当前用户收藏,以及当前文章的评论,因此我们要准备写评论、收藏Bean的Dao和Service

    首先开发数据库中两张表的实体Bean,没有数据库环境的见知识点1,第一个是收藏Bean

    package com.wy.bean;
    
    import java.io.Serializable;
    import java.util.Date;
    
    /**
     * 
     * @ClassName: Collect 
     * @Description: 文章的收藏
     * @author: charles
     * @date: 2020年2月15日 上午8:41:22
     */
    public class Collect  implements Serializable{
    	
    	/**
    	 * @fieldName: serialVersionUID
    	 * @fieldType: long
    	 * @Description: TODO
    	 */
    	private static final long serialVersionUID = 1L;
    	private Integer id;
    	private String text;//文章的标题
    	private String url;//文章的url
    	private Integer userId;//收藏人ID
    	private  User user;//收藏人
    	private Date created;//收藏时间
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	
    	public Integer getUserId() {
    		return userId;
    	}
    	public void setUserId(Integer userId) {
    		this.userId = userId;
    	}
    	public String getText() {
    		return text;
    	}
    	public void setText(String text) {
    		this.text = text;
    	}
    	public String getUrl() {
    		return url;
    	}
    	public void setUrl(String url) {
    		this.url = url;
    	}
    	public User getUser() {
    		return user;
    	}
    	public void setUser(User user) {
    		this.user = user;
    	}
    	public Date getCreated() {
    		return created;
    	}
    	public void setCreated(Date created) {
    		this.created = created;
    	}
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((id == null) ? 0 : id.hashCode());
    		result = prime * result + ((userId == null) ? 0 : userId.hashCode());
    		return result;
    	}
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Collect other = (Collect) obj;
    		if (id == null) {
    			if (other.id != null)
    				return false;
    		} else if (!id.equals(other.id))
    			return false;
    		if (userId == null) {
    			if (other.userId != null)
    				return false;
    		} else if (!userId.equals(other.userId))
    			return false;
    		return true;
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    随后是评论Bean

    package com.wy.bean;
    
    import java.io.Serializable;
    import java.util.Date;
    /**
     * 
     * @ClassName: Comment 
     * @Description: 评论表
     * @author: charles
     * @date: 2020年3月13日 上午11:32:22
     */
    public class Comment implements Serializable {
    
    	/**
    	 * @fieldName: serialVersionUID
    	 * @fieldType: long
    	 * @Description: TODO
    	 */
    	private static final long serialVersionUID = 1L;
    	
    	private Integer id;
    	private Integer userId;//用户id
    	private Integer articleId;//文章id
    	private String content;//评论
    	private Date created;//时间
    	
    	private  User user;
    	private Article article;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public Integer getUserId() {
    		return userId;
    	}
    	public void setUserId(Integer userId) {
    		this.userId = userId;
    	}
    	public Integer getArticleId() {
    		return articleId;
    	}
    	public void setArticleId(Integer articleId) {
    		this.articleId = articleId;
    	}
    	public String getContent() {
    		return content;
    	}
    	public void setContent(String content) {
    		this.content = content;
    	}
    	
    	public Date getCreated() {
    		return created;
    	}
    	public void setCreated(Date created) {
    		this.created = created;
    	}
    	public User getUser() {
    		return user;
    	}
    	public void setUser(User user) {
    		this.user = user;
    	}
    	public Article getArticle() {
    		return article;
    	}
    	public void setArticle(Article article) {
    		this.article = article;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    有了Bean,我们就要开发对应的Dao和Service层,同样第一个是收藏Dao

    package com.wy.dao;
    
    import java.util.List;
    
    
    import org.apache.ibatis.annotations.Param;
    
    import com.wy.bean.Collect;
    
    
    /**
     * 
     * @ClassName: CollectMapper 
     * @Description: 文章收藏
     * @author: charles
     * @date: 2020年4月11日 上午9:03:51
     */
    public interface CollectMapper {
    	/**
    	 * 
    	 * @Title: insert 
    	 * @Description: 增加
    	 * @param collect
    	 * @return
    	 * @return: int
    	 */
    	int insert(Collect collect);
    	/**
    	 * 
    	 * @Title: selects 
    	 * @Description: 查询
    	 * @param collect
    	 * @return
    	 * @return: List
    	 */
    	List<Collect> selects(Collect collect);
    	/**
    	 * 
    	 * @Title: selectCount 
    	 * @Description: 查询注册用户是否收藏text的文章
    	 * @param text
    	 * @param userId
    	 * @return
    	 * @return: int  1:已收藏    0:未收藏
    	 */
    	int selectCount(@Param("text") String text,@Param("userId")Integer userId);
    	/**
    	 * 
    	 * @Title: deleteCollect 
    	 * @Description: 根据ID删除收藏
    	 * @param id
    	 * @return
    	 * @return: int
    	 */
    	int deleteCollect(Integer id);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    以及同步的xml文件

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.wy.dao.CollectMapper">
    
    	<select id="selectCount" resultType="int">
    		select count(id) from cms_collect where user_id=#{userId} and text =#{text}
    	select>
       
    	<insert id="insert">
    		insert into cms_collect (text,user_id,url,created)
    		values(#{text},#{userId},#{url},#{created})
    	insert>
    	
    	
    	<select id="selects" resultType="com.wy.bean.Collect">
    		select * from cms_collect
    		<where>
    			<if test="userId!=null">
    				user_id =#{userId}
    			if>
    		where>
          order by created desc
    	select>
    	
    	<delete id="deleteCollect">
    		delete from cms_collect where id =#{id}
    	delete>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    第二个是评论的Dao

    package com.wy.dao;
    
    import java.util.List;
    
    import com.wy.bean.Comment;
    
    
    /**
     * 
     * @ClassName: CommentMapper 
     * @Description: 评论
     * @author: charles
     * @date: 2020年4月11日 上午11:25:04
     */
    public interface CommentMapper {
    	/**
    	 * 
    	 * @Title: insert 
    	 * @Description: 增加评论
    	 * @param comment
    	 * @return
    	 * @return: int
    	 */
    	int insert(Comment comment);
    	/**
    	 * 
    	 * @Title: selects 
    	 * @Description: 根据文章id 查询评论
    	 * @param articleId
    	 * @return
    	 * @return: List
    	 */
    	List<Comment> selects(Integer articleId);
    	
    	/**
    	 * 
    	 * @Title: updateAritlce 
    	 * @Description: 增加文章的评论数量
    	 * @param id
    	 * @return
    	 * @return: int
    	 */
    	int updateAritlce(Integer id);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    以及同步的xml文件

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.wy.dao.CommentMapper">
    	<insert id="insert">
    		insert into
    		cms_comment(user_id,article_id,content,created)
    		values(#{userId},#{articleId},#{content},#{created})
    	insert>
    
    	<resultMap type="com.wy.bean.Comment" id="commentResultMap">
    		<id column="id" property="id" />
    		<result column="user_id" property="userId" />
    		<result column="article_id" property="articleId" />
    		<result column="content" property="content" />
    		<result column="created" property="created" />
    		
    		<association property="user" javaType="com.wy.bean.User"
    			select="selectById" column="user_id">association>
    
    	resultMap>
    
    
    	<select id="selects" resultMap="commentResultMap">
    		select * from cms_comment where article_id=#{articleId}
    	  order by created desc
    
    	select>
    
    	<select id="selectById" resultType="com.wy.bean.User">
    		select * from cms_user where id=#{id}
    	select>
    	
    	
    	<update id="updateAritlce">
    	 update cms_article set comment_num =comment_num +1  where id =#{id}
    	update>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    然后就是收藏的Service

    package com.wy.service;
    
    import org.apache.ibatis.annotations.Param;
    
    import com.github.pagehelper.PageInfo;
    import com.wy.bean.Collect;
    
    public interface CollectService {
    
    	
    	/**
    	 * 
    	 * @Title: deleteCollect 
    	 * @Description: 根据ID删除收藏
    	 * @param id
    	 * @return
    	 * @return: int
    	 */
    	int deleteCollect(Integer id);
    	/**
    	 * 
    	 * @Title: insert 
    	 * @Description: 增加
    	 * @param collect
    	 * @return
    	 * @return: int
    	 */
    	boolean insert(Collect collect);
    	/**
    	 * 
    	 * @Title: selects 
    	 * @Description: 查询
    	 * @param collect
    	 * @return
    	 * @return: List
    	 */
    	PageInfo<Collect> selects(Collect collect,Integer page,Integer pageSize);
    	
    	
    	/**
    	 * 
    	 * @Title: selectCount 
    	 * @Description: 查询注册用户是否收藏text的文章
    	 * @param text
    	 * @param userId
    	 * @return
    	 * @return: int  1:已收藏    0:未收藏
    	 */
    	int selectCount(@Param("text") String text,@Param("userId")Integer userId);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    以及对应的实现类

    package com.wy.service;
    
    import java.util.List;
    
    
    import javax.annotation.Resource;
    
    import com.wy.utils.StringUtil;
    import org.springframework.stereotype.Service;
    
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import com.wy.bean.Collect;
    import com.wy.dao.CollectMapper;
    import com.wy.utils.CMSException;
    
    @Service
    public class CollectServiceImpl implements CollectService {
    	@Resource
    	private CollectMapper collectMapper;
    
    	@Override
    	public boolean insert(Collect collect) {
    		
    		if(!StringUtil.isHttpUrl(collect.getUrl()))
    			throw new CMSException("url 不合法");
    		
    		return collectMapper.insert(collect) >0;
    	}
    
    	@Override
    	public PageInfo<Collect> selects(Collect collect, Integer page, Integer pageSize) {
    		PageHelper.startPage(page, pageSize);
    		List<Collect> selects = collectMapper.selects(collect);
    		return new PageInfo<Collect>(selects);
    	}
    
    	@Override
    	public int selectCount(String text, Integer userId) {
    		// TODO Auto-generated method stub
    		return collectMapper.selectCount(text, userId);
    	}
    
    	@Override
    	public int deleteCollect(Integer id) {
    		// TODO Auto-generated method stub
    		return collectMapper.deleteCollect(id);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    最后是评论的Service

    package com.wy.service;
    
    import java.util.List;
    
    import com.github.pagehelper.PageInfo;
    import com.wy.bean.Comment;
    
    public interface CommentService {
    
    	
    	/**
    	 * 
    	 * @Title: insert 
    	 * @Description: 增加评论
    	 * @param comment
    	 * @return
    	 * @return: int
    	 */
    	int insert(Comment comment);
    	/**
    	 * 
    	 * @Title: selects 
    	 * @Description: 根据文章id 查询评论
    	 * @param articleId
    	 * @return
    	 * @return: List
    	 */
    	PageInfo<Comment> selects(Integer articleId,Integer page,Integer pageSize);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    以及实现类

    package com.wy.service;
    
    import java.util.List;
    
    
    import javax.annotation.Resource;
    
    import org.springframework.stereotype.Service;
    
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import com.wy.bean.Comment;
    import com.wy.dao.CommentMapper;
    @Service
    public class CommentServiceImpl  implements CommentService{
    	@Resource
    	private CommentMapper commentMapper;
    
    	@Override
    	public int insert(Comment comment) {
    		try {
    			commentMapper.insert(comment);//增加评论
    			commentMapper.updateAritlce(comment.getArticleId());//让评论数量增加1
    			return 1;
    		} catch (Exception e) {
    			e.printStackTrace();
    			throw new RuntimeException("评论失败");
    		}
    		
    	}
    
    	@Override
    	public PageInfo<Comment> selects(Integer articleId, Integer page, Integer pageSize) {
    		PageHelper.startPage(page, pageSize);
    		List<Comment> list = commentMapper.selects(articleId);
    		return new PageInfo<Comment>(list);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    有了Dao和Service,我们就需要在首页的Controller中注入他们

    @Resource
    private CollectService collectService;//收藏
    
    @Resource
    private CommentService commentService;//评论
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注入后我们就可以更改首页查询详情的Controller了,在原先的基础上,查询出是否收藏文章以及文章评论

    /**
    	 *
    	 * @Title: detail
    	 * @Description: 文章详情
    	 * @param id
    	 * @return
    	 * @return: String
    	 */
    	@RequestMapping("detail.do")
    	public String detail(Model model, Integer id, HttpSession session, @RequestParam(defaultValue="1")Integer page) {
    		//查询文章
    		Article article = articleService.select(id);
    		model.addAttribute("article", article);
    
    		//查询文章是否被当前用户收藏
    		// 前提:如果用户已经登录则查询是否收藏
    		User user=(User) session.getAttribute("user");
    		if (null != user) {
    			int isCollect = collectService.selectCount(article.getTitle(), user.getId());
    			model.addAttribute("isCollect", isCollect);
    		}
    
    		//查询评论
    		PageInfo<Comment> info = commentService.selects(id, page, 5);
    		model.addAttribute("info", info);
    
    		return "index/article";
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    现在我们既可运行项目看一下首页详情的效果。注意详情页没有绑定事件呢,正常应该没有动态效果,就是说页面有东西,但没有实际效果。
    在这里插入图片描述


    现在我们在个人中心Controller中准备收藏和评论的请求接收

    @Resource
    private CollectService collectService;//收藏
    
    @Resource
    private CommentService commentService;//评论
    
    /**
     *
     * @Title: collect
     * @Description: 收藏文章
     * @return
     * @return: boolean
     */
    @ResponseBody
    @RequestMapping("collect.do")
    public boolean collect(Collect collect, HttpSession session) {
    	User user = (User) session.getAttribute("user");
    	if (user != null) {// 如果已经登录则执行收藏
    		collect.setUserId(user.getId());// 收藏人
    		collect.setCreated(new Date());// 收藏时间
    		return collectService.insert(collect);
    	}
    	return false;// 没有登录则不执行收藏
    }
    
    /**
     *
     * @Title: collect
     * @Description: 评论文章
     * @return
     * @return: boolean
     */
    @ResponseBody
    @RequestMapping("addComment.do")
    public boolean addComment(Comment comment, HttpSession session) {
    	User user = (User) session.getAttribute("user");
    	if (user != null) {// 如果已经登录则才能评论
    		comment.setUserId(user.getId());// 评论人
    		comment.setCreated(new Date());// 收藏时间
    		return commentService.insert(comment) >0;
    	}
    	return false;// 没有登录则不能评论
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    最后还要给首页详情页绑定JS事件

    <script type="text/javascript">
    	//收藏
    	function collect() {
    		var text = '${article.title}';//获取文章标题
    		var url = window.location.href;//获取文章的url
    
    		$.post("/my/collect.do", {
    			text : text,
    			url : url
    		}, function(flag) {
    			if (flag) {
    				alert("收藏成功");
    				window.location.reload();
    			} else {
    				alert("收藏失败,请登录后再试")
    			}
    		})
    	}
    	//增加评论
    	function addComment() {
    		var content = $("[name='content']").val();
    		var articleId = '${article.id}';
    		$.post("/my/addComment.do", {
    			content : content,
    			articleId : articleId
    		}, function(flag) {
    			if (flag) {
    				alert("评论成功");
    				window.location.reload();
    			} else {
    				alert("评论失败。请登录后重试")
    			}
    		})
    	}
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    最后运行出效果
    在这里插入图片描述
    没有登录是不展示评论的

    但是此时当你点击收藏时会有一个bug,就是在没有登录的情况下会显示收藏成功,但是再次刷新页面的时候页面任然正常,这是因为收藏和评论的Controller被拦截器拦截了,可这两个本身有有着是否有Session的判断,后端的数据就是安全的,但前端收不到返回结果,导致程序混乱直接运行了为真的代码,把两个Controller的拦截器释放就行正常了
    在这里插入图片描述
    回复正常后,我们测试登录后执行收藏、评论
    在这里插入图片描述
    在这里插入图片描述
    到此首页优化完成,至于个人首页中的我的收藏、我的评论留给大家扩展,因为这两个功能核心点太简单了就是查对应的列表展示,最多再多做一个删除评论和取消收藏,所以这两个小功能大家自己做吧,再往后的知识点就该到ES那些重点组件了,本项目目前以上传github :https://github.com/wangyang159/cmsdemo

  • 相关阅读:
    .css和.qss的区别
    SpringBoot的流浪宠物系统
    桥接模式(Bridge Pattern)
    【Leetcode每日一题】 位运算 - 两整数之和(难度⭐)(37)
    你了解Spring Security安全管理框架吗?
    第三方接口重试机制是怎么做的
    从 CPU 讲起,深入理解 Java 内存模型!
    软考高级系统架构设计师系列论文真题六:论信息系统的安全性与保密性设计
    一篇文章让你搞懂__str__和__repr__的异同?
    Chrome浏览器关闭左上角搜索标签页的解决办法
  • 原文地址:https://blog.csdn.net/dudadudadd/article/details/126900465