ssm(springmvc4+spring4+mybatis3)整合实战-个人博客系统-前端页面的开发

ssm(springmvc4+spring4+mybatis3)整合实战-个人博客系统-前端首页的开发

    前面介绍完了util包的各种工具类、service层、model层以及dao层的实现,可以说是分享了一大半了!可能有些博友对于其中的code的作用不是很知晓,但是我相信随着我controller以及页面的开发分享,我想,你会逐渐知晓前面介绍的作用的。特别是比较实用的各种工具类:比如日期处理、加密解密、web文件如图片等的处理、文件下载等等、分页工具类、异步或者同步response工具类等等。

    本篇博文将介绍介绍前端页面的开发。主要有首页的列表展示、首页分页与分类查询、首页数据的全文检索查询、博客详情、博客评论以及源代码或者叫文件下载

    1、首页请求/index可以得到首页,请求/downloadFile可以得到本博客系统的源码压缩包,控制器代码IndexController.java,其中首页博客列表展示时采用了缩略图的形式:这里面采用的技术是jsoup,去检索出博客内容中前三张图片,进行展示

package com.steadyjack.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.steadyjack.entity.Blog;
import com.steadyjack.entity.PageBean;
import com.steadyjack.service.BlogService;
import com.steadyjack.util.PageUtil;
import com.steadyjack.util.StringUtil;
import com.steadyjack.util.WebFileUtil;

/**
 * title:IndexController.java
 * description:前端主页Controller
 * time:2017年1月21日 下午10:28:50
 * author:debug-steadyjack
 */
@Controller
public class IndexController {

	@Resource
	private BlogService blogService;
	
	@RequestMapping("/")
	public String defaultPage(){
		return "redirect:/index";
	}
	
	/**
	 * title:IndexController.java
	 * description:请求主页
	 * time:2017年1月21日 下午10:30:17
	 * author:debug-steadyjack
	 * @param page
	 * @param typeId
	 * @param releaseDateStr
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/index")
	public ModelAndView index(@RequestParam(value="page",required=false)String page,
			@RequestParam(value="typeId",required=false)String typeId,
			@RequestParam(value="releaseDateStr",required=false)String releaseDateStr,
			HttpServletRequest request)throws Exception{
		
		ModelAndView mav=new ModelAndView();
		if(StringUtil.isEmpty(page)){
			page="1";
		}
		Integer pageNo=Integer.parseInt(page);
		
		PageBean pageBean=new PageBean(pageNo,10);
		Map<String,Object> map=new HashMap<String,Object>();
		map.put("start", pageBean.getStart());
		map.put("size", pageBean.getPageSize());
		map.put("typeId", typeId);
		map.put("releaseDateStr", releaseDateStr);
		List<Blog> blogList=blogService.list(map);
		
		for(Blog blog:blogList){
			//用于存放博客内容里面的图片,从而生成缩略图-用于前端页面展示
			List<String> imagesList=blog.getImagesList();
			
			String blogInfo=blog.getContent();
			Document doc=Jsoup.parse(blogInfo);
			
			//查找扩展名是jpg的图片:根据页面需要拿n张图片,这里拿了3张
			Elements jpgs=doc.select("img[src$=.jpg]"); 
			if (jpgs!=null && jpgs.size()>0) {
				for(int i=0;i<jpgs.size();i++){
					Element jpg=jpgs.get(i);
					imagesList.add(jpg.toString());
					if(i==2){
						break;
					}
				}
			}
			
		}
		mav.addObject("blogList", blogList);
		
		//查询参数
		StringBuffer param=new StringBuffer(); 
		if(StringUtil.isNotEmpty(typeId)){
			param.append("typeId="+typeId+"&");
		}
		if(StringUtil.isNotEmpty(releaseDateStr)){
			param.append("releaseDateStr="+releaseDateStr+"&");
		}
		
		Long totalRecord=blogService.getTotal(map);
		Integer pageSize=10;
		String genPagination=PageUtil.genPagination(request.getContextPath()+"/index.html",totalRecord,pageNo,pageSize,param.toString());
		
		//分页、主页、页面title、跳转的页面地址  
		mav.addObject("pageCode",genPagination);
		mav.addObject("mainPage", "foreground/blog/list.jsp");
		mav.addObject("pageTitle","Java开源博客系统");
		mav.setViewName("mainTemp");
		
		return mav;
	}
	
	/**
	 * title:IndexController.java
	 * description:系统功能介绍页面
	 * time:2017年1月22日 下午8:48:10
	 * author:debug-steadyjack
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/download")
	public ModelAndView download()throws Exception{
		ModelAndView mav=new ModelAndView();
		
		mav.addObject("mainPage", "foreground/system/download.jsp");
		mav.addObject("pageTitle","本站源码下载页面_Java开源博客系统");
		mav.setViewName("mainTemp");
		
		return mav;
	}
	
	/**
	 * title:IndexController.java
	 * description:下载系统源码
	 * time:2017年1月22日 下午9:56:12
	 * author:debug-steadyjack
	 * @param request
	 * @throws Exception
	 */
	@RequestMapping("/downloadFile")
	public void downloadFile(@RequestParam(value="fileUrl")String fileUrl,
			@RequestParam(value="fileName")String fileName,HttpServletRequest request,HttpServletResponse response)
			throws Exception{
		WebFileUtil.downloadFile(request, response, fileUrl, fileName);
	}
	
	
	
}
    其实,这个控制器controller就已经展示了springmvc的角色,彻底对springmvc的工作原理进行淋漓尽致的应用。看过springmvc的宏观工作原理的博友都知道,springmvc的工作原理大概是这样的:

1、客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.

2、DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。

3、DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。

4、Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet。

5、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。

6、Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端

   看完之后,是不是觉得我的那个controller确实表示的淋漓尽致。只不过,现在自己写的时候,可以对上面的写法进行诸多优化,而且随着spring4.3还是4.2起对于controller的写法更加简洁了。

   比如对于请求参数的写法,可以用参数封装(当然啦,这个可能不是spring4.x的功能),controller返回的一般是String,即一个视图的地址等等。

   对于springmvc的详细介绍可以另外看多几篇博客。

   2、完了之后,介绍一下博客详情、博客的全文检索模糊查询(这里采用lucene实现)以及博客的分页(在这里采用 同步刷新)logController.java以及评论控制器CommentController.java:

package com.steadyjack.controller;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.steadyjack.entity.Blog;
import com.steadyjack.lucene.BlogIndex;
import com.steadyjack.service.BlogService;
import com.steadyjack.service.CommentService;
import com.steadyjack.util.StringUtil;

/**
 * title:BlogController.java
 * description:前端博客Controller层
 * time:2017年1月17日 下午9:44:19
 * author:debug-steadyjack
 */
@Controller
@RequestMapping("/blog")
public class BlogController {

	@Resource
	private BlogService blogService;
	
	@Resource
	private CommentService commentService;
	
	// 博客索引
	private BlogIndex blogIndex=new BlogIndex();
	
	
	/**
	 * title:BlogController.java
	 * description:博客详细信息
	 * time:2017年1月17日 下午9:51:50
	 * author:debug-steadyjack
	 * @param id
	 * @param request
	 * @throws Exception
	 */
	@RequestMapping("/articles/{id}")
	public ModelAndView details(@PathVariable Integer id,HttpServletRequest request)throws Exception{
		ModelAndView modelAndView=new ModelAndView();
		
		Blog blog=blogService.findById(id);
		String keyWords=blog.getKeyWord();
		
		if(StringUtil.isNotEmpty(keyWords)){
			String arr[]=keyWords.split(" ");
			modelAndView.addObject("keyWords",StringUtil.filterWhite(Arrays.asList(arr)));			
		}else{
			modelAndView.addObject("keyWords",null);			
		}
		
		modelAndView.addObject("blog", blog);
		
		Integer clickHit=blog.getClickHit();
		clickHit = clickHit==null?0:clickHit+1;
		//博客点击次数加1
		blog.setClickHit(clickHit); 
		blogService.update(blog);
		
		Map<String,Object> map=new HashMap<String,Object>();
		//查询审核通过的评论
		map.put("blogId", blog.getId());
		map.put("state", 1);
		
		//System.out.println(request.getServletContext().getContextPath());
		
		modelAndView.addObject("commentList", commentService.list(map)); 
		modelAndView.addObject("pageCode", this.genUpAndDownPageCode(blogService.getLastBlog(id),blogService.getNextBlog(id),request.getServletContext().getContextPath()));
		modelAndView.addObject("mainPage", "foreground/blog/view.jsp");
		modelAndView.addObject("pageTitle",blog.getTitle());
		modelAndView.setViewName("mainTemp");
		
		//查询审核通过的评论
		return modelAndView;
	}
	
	/**
	 * title:BlogController.java
	 * description:根据查询信息查询相关博客信息
	 * time:2017年1月17日 下午11:11:29
	 * author:debug-steadyjack
	 * @param q
	 * @param page
	 * @param request
	 * @return ModelAndView
	 * @throws Exception
	 */
	@RequestMapping("/q")
	public ModelAndView search(@RequestParam(value="q",required=false)String q,@RequestParam(value="page",required=false)String page,HttpServletRequest request)throws Exception{
		if(StringUtil.isEmpty(page)){
			page="1";
		}
		ModelAndView mav=new ModelAndView();
		
		mav.addObject("mainPage", "foreground/blog/result.jsp");
		
		blogIndex.setRequest(request);
		List<Blog> blogList=blogIndex.searchBlog(q.trim());
		Integer pageNo=Integer.parseInt(page);
		Integer pageSize=10;
		Integer toIndex=blogList.size()>=pageNo*pageSize?pageNo*pageSize:blogList.size();
		
		//list的subList是分页的一种:返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图
		mav.addObject("blogList",blogList.subList((pageNo-1)*pageSize, toIndex));
		mav.addObject("pageCode",this.genUpAndDownPageCode(pageNo, blogList.size(), q,10,request.getServletContext().getContextPath()));
		mav.addObject("q",q);
		mav.addObject("resultTotal",blogList.size());
		mav.addObject("pageTitle","搜索关键字'"+q+"'结果页面_Java修炼之博客系统");
		mav.setViewName("mainTemp");
		
		return mav;
	}
	
	/**
	 * title:BlogController.java
	 * description: 获取下一篇博客和下一篇博客
	 * time:2017年1月17日 下午10:14:03
	 * author:debug-steadyjack
	 * @param lastBlog
	 * @param nextBlog
	 * @param projectContext
	 * @return String
	 */
	private String genUpAndDownPageCode(Blog lastBlog,Blog nextBlog,String projectContext){
		StringBuffer pageCode=new StringBuffer();
		if(lastBlog==null || lastBlog.getId()==null){
			pageCode.append("<p>上一篇:没有了</p>");
		}else{
			pageCode.append("<p>上一篇:<a href='"+projectContext+"/blog/articles/"+lastBlog.getId()+".html'>"+lastBlog.getTitle()+"</a></p>");
		}
		if(nextBlog==null || nextBlog.getId()==null){
			pageCode.append("<p>下一篇:没有了</p>");
		}else{
			pageCode.append("<p>下一篇:<a href='"+projectContext+"/blog/articles/"+nextBlog.getId()+".html'>"+nextBlog.getTitle()+"</a></p>");
		}
		return pageCode.toString();
	}
	
	/**
	 * 获取上一页,下一页代码 查询博客用到(简单的分页)
	 * @param page 当前页
	 * @param totalNum 总记录数
	 * @param q 查询关键字
	 * @param pageSize 每页大小
	 * @param projectContext
	 * @return
	 */
	private String genUpAndDownPageCode(Integer page,Integer totalNum,String q,Integer pageSize,String projectContext){
		long totalPage=totalNum%pageSize==0?totalNum/pageSize:totalNum/pageSize+1;
		StringBuffer pageCode=new StringBuffer();
		if(totalPage==0){
			return "";
		}else{
			pageCode.append("<nav>");
			pageCode.append("<ul class='pager' >");
			if(page>1){
				pageCode.append("<li><a href='"+projectContext+"/blog/q.html?page="+(page-1)+"&q="+q+"'>上一页</a></li>");
			}else{
				pageCode.append("<li class='disabled'><a href='#'>上一页</a></li>");
			}
			if(page<totalPage){
				pageCode.append("<li><a href='"+projectContext+"/blog/q.html?page="+(page+1)+"&q="+q+"'>下一页</a></li>");				
			}else{
				pageCode.append("<li class='disabled'><a href='#'>下一页</a></li>");				
			}
			pageCode.append("</ul>");
			pageCode.append("</nav>");
		}
		return pageCode.toString();
	}
}

    对于评论控制器,在这里比较简单,只是用于游客进行ip评论(前期没做用户那一块的管理,有兴趣的博友可以自己搞一套!)CommentController.java:

package com.steadyjack.controller;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONObject;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.steadyjack.entity.Blog;
import com.steadyjack.entity.Comment;
import com.steadyjack.service.BlogService;
import com.steadyjack.service.CommentService;
import com.steadyjack.util.ResponseUtil;

/**
 * 评论Controller层
 * @author Administrator
 *
 */
@Controller
@RequestMapping("/comment")
public class CommentController {
	
	@Resource
	private CommentService commentService;
	
	@Resource
	private BlogService blogService;
	
	/**
	 * title:CommentController.java
	 * description:添加或者修改评论
	 * time:2017年1月23日 下午8:02:05
	 * author:debug-steadyjack
	 * @param comment
	 * @param imageCode
	 * @param request
	 * @param response
	 * @param session
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/save")
	public String save(Comment comment,@RequestParam("imageCode") String imageCode,
			HttpServletRequest request,HttpServletResponse response,HttpSession session)throws Exception{
		//获取系统生成的验证码
		String sRand=(String) session.getAttribute("sRand");
		
		JSONObject result=new JSONObject();
		
		//操作的记录条数
		int resultTotal=0; 
		if(!imageCode.equals(sRand)){
			result.put("success", false);
			result.put("errorInfo", "验证码填写错误!");
		}else{
			//获取用户IP
			String userIp=request.getRemoteAddr(); 
			comment.setUserIp(userIp);
			if(comment.getId()==null){
				resultTotal=commentService.add(comment);
				//该博客的回复次数加1
				Blog blog=blogService.findById(comment.getBlog().getId());
				blog.setReplyHit(blog.getReplyHit()+1);
				blogService.update(blog);
			}else{
				
			}
			if(resultTotal>0){
				result.put("success", true);
			}else{
				result.put("success", false);
			}
		}
		ResponseUtil.write(response, result);
		return null;
	}

}

    最后一个介绍一下“关于博主”/aboutMe请求以及博主登录/login进行认证,通过之后进入后台BloggerController.java:

package com.steadyjack.controller;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.steadyjack.entity.Blogger;
import com.steadyjack.service.BloggerService;
import com.steadyjack.util.CryptographyUtil;

/**
 * title:BloggerController.java
 * description:博主Controller层
 * time:2017年1月23日 下午10:01:10
 * author:debug-steadyjack
 */
@Controller
@RequestMapping("/blogger")
public class BloggerController {

	@Resource
	private BloggerService bloggerService;
	
	/**
	 * title:BloggerController.java
	 * description:用户登录
	 * time:2017年1月23日 下午10:01:20
	 * author:debug-steadyjack
	 * @param blogger
	 * @param request
	 * @return
	 */
	@RequestMapping("/login")
	public String login(Blogger blogger,HttpServletRequest request){
		Subject subject=SecurityUtils.getSubject();
		UsernamePasswordToken token=new UsernamePasswordToken(blogger.getUserName(), CryptographyUtil.md5(blogger.getPassword(), "debug"));
		try{
			//登录验证
			subject.login(token); 
			return "redirect:/admin/main.jsp";
		}catch(Exception e){
			e.printStackTrace();
			request.setAttribute("blogger", blogger);
			request.setAttribute("errorInfo", "用户名或密码错误!");
			return "login";
		}
	}
	
	/**
	 * title:BloggerController.java
	 * description:查找博主信息
	 * time:2017年1月23日 下午10:12:45
	 * author:debug-steadyjack
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/aboutMe")
	public ModelAndView aboutMe()throws Exception{
		ModelAndView mav=new ModelAndView();
		
		mav.addObject("blogger",bloggerService.find());
		mav.addObject("mainPage", "foreground/blogger/info.jsp");
		mav.addObject("pageTitle","关于博主_Java开源博客系统");
		mav.setViewName("mainTemp");
		
		return mav;
	}
}

    认证的过程走的是shiro框架的提供MyRealm.java(这在前面已经讲过了):

package com.steadyjack.realm;

import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import com.steadyjack.entity.Blogger;
import com.steadyjack.service.BloggerService;

/**
 * title:MyRealm.java
 * description:自定义Realm(域)
 * time:2017年1月22日 下午10:50:57
 * author:debug-steadyjack
 */
public class MyRealm extends AuthorizingRealm{

	@Resource
	private BloggerService bloggerService;
	
	/**
	 * 为当限前登录的用户授予角色和权
	 * (由于目前系统没有啥资源且只有admin超级用户,故而没写授予角色、权限(资源)逻辑)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;
	}

	/**
	 * 验证当前登录的用户
	 * (成功时,将登陆用户绑定到会话中;失败时,其实会报各种exception,理当抛出用于前端页面展示(后期实现))
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//获取身份(在这里指 用户名)-凭证(在这里指 密码)
		String userName=(String)token.getPrincipal();
		Blogger blogger=bloggerService.getByUserName(userName);
		if(blogger!=null){
			//当前用户信息存到session中
			SecurityUtils.getSubject().getSession().setAttribute("currentUser", blogger); 
			AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(blogger.getUserName(),blogger.getPassword(),getName());
			return authcInfo;
		}else{
			return null;				
		}
	}

}

    最后是贴出效果:










     最后,把WebContent下的页面分享出来:前端用的是bootstrap,后端页面用的是easyui,目录如图:


    页面以及样式来这里下载:

     如果有相关问题:如想找我付费开发其他功能,讨论其中相关问题等等,可以来以下两群找我,我叫debug!

     Java开源技术交流:583522159     鏖战八方群:391619659

  • 1
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 1
    评论
个人博客系统主要用于发表个人博客,记录个人生活日常,学习心得,技术分享等,供他人浏览,查阅,评论等。本系统结构如下: (1)博主端: 登录模块:登入后台管理系统:首先进入登录页面,需要输入账号和密码。它会使用Shiro进行安全管理,对前台输入的密 码进行加密运算,然后与数据库中的进行比较。成功后才能登入后台系统博客管理模块: 博客管理功能分为写博客博客信息管理。写博客是博主用来发表编写博客的,需要博客标题,然后选择博 客类型,最后将博客内容填入百度的富文本编辑器中,点击发布博客按钮即可发布博客博客类别管理模块:博主类别管理系统可以添加,修改和删除博客类型名称和排序序号。将会显示到首页的按日志类别区域。 游客可以从这里查找相关的感兴趣的博客内容 评论信息管理模块:评论管理功能分为评论审核和评论信息管理两部分。评论审核是当有游客或自己发表了评论之后,博主需 要在后台管理系统中审核评论。若想将此评论显示在页面上则点击审核通过,否则点击审核不通过。 个人信息管理模块:修改博主的个人信息,可以修改昵称,个性签名,可以添加个人头像,修改个人简介; 系统管理功能模块:友情链接管理,修改密码,刷新系统缓存和安全退出,友情链接管理可以添加,修改,删除友情链接网址 (2)游客端: 查询博客: 查询具体哪一篇博客 查看博客内容: 查看博客内容 查看博主个人信息:查看博主个人简介 发表评论: 可以评论具体某篇博客 友情链接: 查看友情链接

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修罗debug

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值