基于Springmvc+MyBatis+Spring+Bootstrap+EasyUI+Mysql的个人博客系统

基于Springmvc+MyBatis+Spring+Bootstrap+EasyUI+Mysql的个人博客系统 1, 项目介绍 使用Maven3+Spring4+Springmvc+Mybatis3架构;数据库使用Mysql

本文包含相关资料包-----> 点击直达获取<-------

基于Springmvc+MyBatis+Spring+Bootstrap+EasyUI+Mysql的个人博客系统

1. 项目介绍

  1. 使用Maven3+Spring4+Springmvc+Mybatis3架构;数据库使用Mysql,数据库连接池使用阿里巴巴的Druid;
  2. 使用Bootstrap3 UI框架实现博客的分页显示,博客分类,文章归类显示;完成用户评论和分享功能;
  3. 使用EasyUI实现后台对博客、博客类别、用户评论、博主信息的管理,包括增删改查,文件上传等;实现刷新后台缓存等功能;
  4. 使用Shiro作为项目安全框架,验证不同url的请求,包括后台博主的登陆;
  5. 实现Lucene对全站的检索功能,对检索出的博客标题和内容实现高亮显示;
  6. 使用百度的Ueditor编辑器实现写博客功能,支持单图、多图上传,支持截图上传,支持代码高亮特性等。

2.数据库设计

2.1表结构

博客表

博主表

博客类型表

评论表

友情链接表

2.2ER图

3.项目设计

3.1项目配置

```xml

<!-- 鑷姩鎵弿鍖呬腑鐨刡ean -->
<context:component-scan base-package="ssm.blog.*" />

<!-- 閰嶇疆鏁版嵁婧愶紝浣跨敤闃块噷宸村反杩炴帴姹燚ruid -->
<bean id="dataSource" >
  <property name="url" value="jdbc:mysql://localhost:3306/db_blog"/>
  <property name="username" value="root"/>
  <property name="password" value="root"/>
</bean>

<!-- 閰嶇疆mybatis鐨剆qlSessionFactory -->
<bean id="sqlSessionFactory" >
  <property name="dataSource" ref="dataSource" />
  <!-- 鑷姩鎵弿mappers.xml鏂囦欢 -->
  <property name="mapperLocations" value="classpath:ssm/blog/mappers/*.xml"></property>
  <!-- 鍔犺浇mybatis鍏ㄥ眬閰嶇疆鏂囦欢 -->
  <property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>

<!-- 鎵弿mapper鎺ュ彛锛堝嵆dao锛夛紝Spring浼氳嚜鍔ㄦ煡鎵惧叾涓嬬殑绫?-->
<bean >
  <property name="basePackage" value="ssm.blog.dao" />
  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>

<!-- 浜嬪姟绠$悊锛坱ransaction manager锛?-->
<bean id="transactionManager"
  >
  <property name="dataSource" ref="dataSource" />
</bean>

<!-- 鑷畾涔塕ealm -->
<bean id="myRealm" />

<!-- 瀹夊叏绠$悊鍣?-->
<bean id="securityManager" >
  <property name="realm" ref="myRealm" />
</bean>

<!-- Shiro杩囨护鍣?-->
<bean id="shiroFilter" >
  <!-- Shiro鐨勬牳蹇冨畨鍏ㄦ帴鍙?杩欎釜灞炴ф槸蹇呴』鐨?-->
  <property name="securityManager" ref="securityManager" />
  <!-- 韬唤璁よ瘉澶辫触锛屽垯璺宠浆鍒扮櫥褰曢〉闈㈢殑閰嶇疆 -->
  <property name="loginUrl" value="/login.jsp" />
  <!-- 鏉冮檺璁よ瘉澶辫触锛屽垯璺宠浆鍒版寚瀹氶〉闈紝鍥犱负涓汉鍗氬灏变竴涓汉鐧婚檰锛屽氨涓嶉渶瑕佹潈闄愪簡 -->
  <!-- <property name="unauthorizedUrl" value="/unauthorized.jsp" /> -->
  <!-- Shiro杩炴帴绾︽潫閰嶇疆,鍗宠繃婊ら摼鐨勫畾涔?-->
  <property name="filterChainDefinitions">
    <value>
      /login=anon
      /admin/**=authc
    </value>
  </property>
</bean>

<!-- 淇濊瘉瀹炵幇浜哠hiro鍐呴儴lifecycle鍑芥暟鐨刡ean鎵ц -->
<bean id="lifecycleBeanPostProcessor" />

<!-- 寮鍚疭hiro娉ㄨВ -->
<bean
  
  depends-on="lifecycleBeanPostProcessor" />
<bean
  >
  <property name="securityManager" ref="securityManager" />
</bean>

<!-- 閰嶇疆浜嬪姟閫氱煡灞炴?-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <!-- 瀹氫箟浜嬪姟浼犳挱灞炴?-->
  <tx:attributes>
    <tx:method name="insert*" propagation="REQUIRED" />
    <tx:method name="update*" propagation="REQUIRED" />
    <tx:method name="edit*" propagation="REQUIRED" />
    <tx:method name="save*" propagation="REQUIRED" />
    <tx:method name="add*" propagation="REQUIRED" />
    <tx:method name="new*" propagation="REQUIRED" />
    <tx:method name="set*" propagation="REQUIRED" />
    <tx:method name="remove*" propagation="REQUIRED" />
    <tx:method name="delete*" propagation="REQUIRED" />
    <tx:method name="change*" propagation="REQUIRED" />
    <tx:method name="check*" propagation="REQUIRED" />
    <tx:method name="get*" propagation="REQUIRED" read-only="true" />
    <tx:method name="find*" propagation="REQUIRED" read-only="true" />
    <tx:method name="load*" propagation="REQUIRED" read-only="true" />
    <tx:method name="*" propagation="REQUIRED" read-only="true" />
  </tx:attributes>
</tx:advice>

<!-- 閰嶇疆浜嬪姟鍒囬潰 -->
<aop:config>
  <aop:pointcut id="pointCut" expression="execution(* ssm.blog.service.*.*(..))" />
  <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut" />
</aop:config>

```

3.2监听器

```java package ssm.blog.listener;

import java.util.List;

import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;

import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;

import ssm.blog.entity.Blog; import ssm.blog.entity.BlogType; import ssm.blog.entity.Blogger; import ssm.blog.entity.Link; import ssm.blog.service.BlogService; import ssm.blog.service.BlogTypeService; import ssm.blog.service.BloggerService; import ssm.blog.service.LinkService;

@Component public class InitBloggerData implements ServletContextListener, ApplicationContextAware {

private static ApplicationContext applicationContext;

public void contextInitialized(ServletContextEvent sce) {
    System.out.println(applicationContext);
    //先获取servlet上下文
    ServletContext application = sce.getServletContext();

    //根据spring的上下文获取bloggerService这个bean
    BloggerService bloggerService = (BloggerService) applicationContext.getBean("bloggerService");
    //获取博主信息
    Blogger blogger = bloggerService.getBloggerData();
    //由于密码也获取到了,比较敏感,我们也不需要这个,所以把密码清空掉
    blogger.setPassword(null);
    //将博主信息存入application域中
    application.setAttribute("blogger", blogger);

    //同上,获取友情链接信息
    LinkService linkService = (LinkService) applicationContext.getBean("linkService");
    List<Link> linkList = linkService.getLinkData(); 
    application.setAttribute("linkList", linkList);

    //同上,获取博客类别信息
    BlogTypeService blogTypeService = (BlogTypeService) applicationContext.getBean("blogTypeService");
    List<BlogType> blogTypeList = blogTypeService.getBlogTypeData();
    application.setAttribute("blogTypeList", blogTypeList);

    //同上,获取博客信息,按照时间分类的
    BlogService blogService = (BlogService) applicationContext.getBean("blogService");
    List<Blog> blogTimeList = blogService.getBlogData();
    application.setAttribute("blogTimeList", blogTimeList);
}

public void contextDestroyed(ServletContextEvent sce) {
    // TODO Auto-generated method stub

}

public void setApplicationContext(ApplicationContext applicationContext) 
        throws BeansException {
    InitBloggerData.applicationContext = applicationContext;
}

}

```

3.3博客全文索引

```java /* * @Description 博客索引类 * @author Ni Shengwu * / public class BlogIndex {

private Directory dir;

private IndexWriter getWriter() throws Exception {      
    dir = FSDirectory.open(Paths.get("D:\\blog_index"));
    SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer();
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    IndexWriter writer = new IndexWriter(dir, config);  
    return writer;
}

//添加博客索引
public void addIndex(Blog blog)  throws Exception {
    IndexWriter writer = getWriter();
    Document doc = new Document();
    doc.add(new StringField("id", String.valueOf(blog.getId()), Field.Store.YES));
    doc.add(new TextField("title", blog.getTitle(), Field.Store.YES));
    doc.add(new StringField("releaseDate", DateUtil.formatDate(new Date(), "yyyy-MM-dd"), Field.Store.YES));        
    doc.add(new TextField("content", blog.getContentNoTag(), Field.Store.YES));     
    writer.addDocument(doc);
    writer.close();
}

//删除指定博客的索引
public void deleteIndex(String blogId) throws Exception {
    IndexWriter writer = getWriter();
    writer.deleteDocuments(new Term("id", blogId));
    writer.forceMergeDeletes();//强制删除
    writer.commit();
    writer.close();
}

//更新博客索引
public void updateIndex(Blog blog) throws Exception {
    IndexWriter writer = getWriter();
    Document doc = new Document();
    doc.add(new StringField("id", String.valueOf(blog.getId()), Field.Store.YES));
    doc.add(new TextField("title", blog.getTitle(), Field.Store.YES));
    doc.add(new StringField("releaseDate", DateUtil.formatDate(new Date(), "yyyy-MM-dd"), Field.Store.YES));        
    doc.add(new TextField("content", blog.getContentNoTag(), Field.Store.YES));     
    writer.updateDocument(new Term("id", String.valueOf(blog.getId())), doc);
    writer.close();
}

//查询博客索引信息
public List<Blog> searchBlog(String q) throws Exception {

    dir = FSDirectory.open(Paths.get("D:\\blog_index"));
    IndexReader reader = DirectoryReader.open(dir);
    IndexSearcher search = new IndexSearcher(reader);
    BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
    SmartChineseAnalyzer analyzer = new SmartChineseAnalyzer();

    QueryParser parser1 = new QueryParser("title", analyzer); //查询标题
    Query query1 = parser1.parse(q);

    QueryParser parser2 = new QueryParser("content", analyzer); //查询内容
    Query query2 = parser2.parse(q);

    booleanQuery.add(query1, BooleanClause.Occur.SHOULD);
    booleanQuery.add(query2, BooleanClause.Occur.SHOULD);

    TopDocs hits = search.search(booleanQuery.build(), 100);

    QueryScorer scorer = new QueryScorer(query1);//使用title得分高的排前面
    Fragmenter fragmenter = new SimpleSpanFragmenter(scorer); //得分高的片段
    SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter("<b><font color='red'>", "</font></b>");
    Highlighter highlighter = new Highlighter(simpleHTMLFormatter, scorer); //高亮显示
    highlighter.setTextFragmenter(fragmenter); //将得分高的片段设置进去

    List<Blog> blogIndexList = new LinkedList<Blog>(); //用来封装查询到的博客
    for(ScoreDoc score : hits.scoreDocs) {
        Document doc = search.doc(score.doc);
        Blog blog = new Blog();
        blog.setId(Integer.parseInt(doc.get("id")));
        blog.setReleaseDateStr(doc.get("releaseDate"));
        String title = doc.get("title");
        String content = doc.get("content");
        if(title != null) {
            TokenStream tokenStream = analyzer.tokenStream("title", new StringReader(title));
            String hTitle = highlighter.getBestFragment(tokenStream, title);
            if(StringUtil.isEmpty(hTitle)) {
                blog.setTitle(title);
            } else {
                blog.setTitle(hTitle);
            }
        }
        if(content != null) {
            TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(content));
            String hContent = highlighter.getBestFragment(tokenStream, content);
            if(StringUtil.isEmpty(hContent)) {
                if(content.length() > 100) { //如果没查到且content内容又大于100的话
                    blog.setContent(content.substring(0, 100)); //截取100个字符
                } else {
                    blog.setContent(content);
                }
            } else {
                blog.setContent(hContent);
            }
        }
        blogIndexList.add(blog);
    }

    return blogIndexList;
}

}

```

3.4工具类

md5加密工具类

```java

/* * md5加密工具类 * @author Administrator * / public class CryptographyUtil {

/**
 * @Description 使用Shiro中的md5加密
 * @param str
 * @param salt
 * @return
 */
public static String md5(String str,String salt){
    //Md5Hash是Shiro中的一个方法
    return new Md5Hash(str, salt).toString();
}

//我自己生成一下测试用的
public static void main(String[] args) {
    String password="123456";

    System.out.println("Md5加密:"+CryptographyUtil.md5(password, "javacoder"));
}

}

```

分页工具类

```java /* * 分页工具类 * @author Administrator * / public class PageUtil {

/**
 * 生成分页代码
 * @param targetUrl 目标地址
 * @param totalNum 总记录数
 * @param currentPage 当前页
 * @param pageSize 每页大小
 * @return
 */
public static String genPagination(
                                    String targetUrl, //目标url
                                    long totalNum,    //总记录数
                                    int currentPage,  //当前页
                                    int pageSize,     //每页显示记录数
                                    String param) {   //参数
    //计算总页数
    long totalPage = totalNum % pageSize==0 ? totalNum/pageSize : totalNum/pageSize+1; 
    if(totalPage == 0){
        return "未查询到数据";
    }else{
        StringBuffer pageCode = new StringBuffer();
        if(currentPage > 1) {
            pageCode.append("<li><a href='" + targetUrl + "?page=1&" + param + "'>首页</a></li>");
            pageCode.append("<li><a href='" + targetUrl + "?page=" + (currentPage-1) + "&" + param + "'>上一页</a></li>");         
        }else{
            pageCode.append("<li class='disabled'><a>首页</a></li>");
            pageCode.append("<li class='disabled'><a>上一页</a></li>");        
        }
        for(int i = currentPage - 2; i <= currentPage + 2; i++) {
            if(i < 1 || i > totalPage) {
                continue;
            }
            if(i == currentPage) {
                pageCode.append("<li class='active'><a href='" + targetUrl + "?page=" + i + "&" + param + "'>" + i + "</a></li>");  
            }else{
                pageCode.append("<li><a href='" + targetUrl + "?page=" + i + "&" + param + "'>" + i + "</a></li>"); 
            }
        }
        if(currentPage < totalPage) {
            pageCode.append("<li><a href='" + targetUrl + "?page=" + (currentPage+1) + "&" + param + "'>下一页</a></li>");
            pageCode.append("<li><a href='" + targetUrl + "?page=" + totalPage + "&" + param + "'>尾页</a></li>");
        }else{
            pageCode.append("<li class='disabled'><a>下一页</a></li>");    
            pageCode.append("<li class='disabled'><a>尾页</a></li>");
        }
        return pageCode.toString();
    }
}

public static String getPrevAndNextPageCode(Blog prev, Blog next, String projectContent) {
    StringBuffer pageCode = new StringBuffer();
    if(prev == null || prev.getId() == null) {
        pageCode.append("<p>上一篇:无</P>");
    } else {
        pageCode.append("<p>上一篇:<a href='" + projectContent + "/blog/articles/" + prev.getId() + ".html'>" + prev.getTitle() + "</a></p>");
    }

    if(next == null || next.getId() == null) {
        pageCode.append("<p>下一篇:无</P>");
    } else {
        pageCode.append("<p>上一篇:<a href='" + projectContent + "/blog/articles/" + next.getId() + ".html'>" + next.getTitle() + "</a></p>");
    }

    return pageCode.toString();
}

//Lucence搜索博客结果的分页
public static String getUpAndDownPageCode (
        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/search.html?page="+(page-1)+"&q="+q+"'>上一页</a></li>");
        } else {
            pageCode.append("<li class='disabled'><a>上一页</a></li>");
        }
        if(page < totalPage) {
            pageCode.append("<li><a href='"+projectContext+"/blog/search.html?page="+(page+1)+"&q="+q+"'>下一页</a></li>");
        } else {
            pageCode.append("<li class='disabled'><a>下一页</a></li>");
        }
        pageCode.append("</ul>");
        pageCode.append("<nav>");
        pageCode.append("<nav>");
        pageCode.append("<nav>");
    }

    return pageCode.toString();
}

}

```

4.项目展示

4.1 前台效果展示

1. 博客主页显示

2. 侧边栏显示

3. 博客内容显示

4. 搜索结果显示

5. 评论模块显示

4.2后台效果展示

1. 博主登陆

2. 修改博主信息

3. 写博客功能

4. 博客管理

5. 添加博客类别等等

5.总结

后台的其他功能就不一个个展示了,都差不多。

参考文献

  • 一种Web应用框架的设计与实现(·河北师范大学)
  • 基于OAuth2.0协议的企业分布式授权系统设计与实现(华中科技大学·支猛)
  • 基于SSH框架的博客用户分享平台的设计与实现(河北工业大学·刘磊)
  • 基于WEB2.0的教育博客应用与研究(北京化工大学·缪洪霞)
  • 基于SSH框架的企业内博客系统的设计与实现(山东大学·柳青)
  • 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航)
  • 基于SSH框架的企业内博客系统的设计与实现(山东大学·柳青)
  • 基于MVC设计模式的博客系统的设计与实现(大连理工大学·侯林)
  • 基于SSH的手机网站的设计与实现(东北大学 ·陶志刚)
  • 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航)
  • 一种Web应用框架的设计与实现(·河北师范大学)
  • 基于J2EE的网上交友系统的设计与实现(大连理工大学·姚岚)
  • 基于SSH框架的企业内博客系统的设计与实现(山东大学·柳青)
  • 基于MD5改进算法的安全教师博客系统设计及开发(湖南大学·刘曼春)
  • 基于SSH架构的个人空间交友网站的设计与实现(北京邮电大学·隋昕航)

本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:毕设海岸 ,原文地址:https://m.bishedaima.com/yuanma/35625.html

相关推荐

发表回复

登录后才能评论