文章目录

  • 博客管理系统介绍
  • 系统实现的功能点
  • 博客设计技术
  • 前端技术
  • 后端技术
  • 数据库设计
  • 详解博客
  • 搭建博客整体目录结构
  • 配置SSM框架所需的依赖等
  • SSM相关的开发
  • MyBatis相关开发
  • Spring相关开发
  • SpringMVC相关开发
  • 项目开发
  • 一、登录界面
  • 1、效果展示:
  • 2、前端
  • 前端login.jsp页面
  • 后端
  • 1、dao层开发
  • 2、Service层开发
  • 3、Controller层开发
  • 存在的问题
  • 二、新增文章页面展示
  • 前端
  • 新增文章页面后端开发
  • 1、dao层开发
  • 2、Service层开发
  • 3、Controller层开发
  • 三、文章保存同步到数据库(操作文章使用Article类)
  • 要考虑的问题
  • 文章同步的后端开发
  • 1、开发dao层
  • 2、开发Service层
  • 3、开发controller层
  • 四、文章列表显示
  • 展示效果页面
  • 前端
  • 1、jsp页面
  • 2、相应的js文件:
  • 后端
  • 1、dao层开发
  • 2、Service层开发
  • Controller层开发
  • 需要考虑的问题


博客管理系统介绍

基于SSM框架,实现博客管理系统,可以进行新增文章、文章浏览等功能。本文重点讲解后端部分,前端内容暂不介绍。

系统实现的功能点

1、用户权限管理:普通用户只能浏览文章,管理员用户可以编写文章
		2、博客列表展示:文章按发布时间展示,展示内容包括:博客类别、标签、博客名称、作者名、发布时间、浏览量、博客内容概括
		3、博客详情页面展示:包括博客名称、作者、时间、标签、类别
		4、博客后台列表:博客检索、博客列表、博客操作
		5、新增博客功能:支持富文本编辑

博客设计技术

前端技术

前端技术使用:jsp、Ajax、前端框架bootstrap、富文本编辑器:百度UEditor

后端技术

后端技术使用:SSM框架、Java、MySQL数据库、JSON数据处理

数据库设计

用户表(t_manager):账号id、账号名称、账号密码

文章表(t_article):文章id、分类id、标题、内容、文章简介、状态、作者、发表时间、浏览量。

博客/标签对应表(t_article_tag):文章id、标签id

标签表(t_tag):标签id、标签名称

类别表(t_category):类别id、类别名称、图片样式、别名、排序

文章表: 
t_article | CREATE TABLE `t_article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `categoryId` int(11) NOT NULL COMMENT '分类id',
  `title` varchar(40) NOT NULL COMMENT '标题',
  `content` blob NOT NULL COMMENT '内容',
  `decription` varchar(500) NOT NULL COMMENT '文章简介 用于列表显示',
  `statue` int(11) NOT NULL DEFAULT '0' COMMENT '状态 0:正常  1:不执行',
  `author` varchar(15) DEFAULT '张宇轩' COMMENT '作者',
  `createTime` datetime NOT NULL COMMENT '发表时间',
  `showCount` int(11) NOT NULL DEFAULT '0' COMMENT '浏览量',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='文章表' 

文章标签对应表:
t_article_tag | CREATE TABLE `t_article_tag` (
  `articleId` int(11) NOT NULL COMMENT '文章Id',
  `tagId` int(11) NOT NULL COMMENT '标签Id',
  PRIMARY KEY (`articleId`,`tagId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章标签中间表'

标签表:
| t_tag | CREATE TABLE `t_tag` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tagName` varchar(25) NOT NULL COMMENT '标签名称 唯一',
  PRIMARY KEY (`id`),
  UNIQUE KEY `tagName_UNIQUE` (`tagName`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8 COMMENT='标签表'

类别表:
 t_category | CREATE TABLE `t_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `categoryName` varchar(20) NOT NULL COMMENT '分类名称 唯一',
  `iconClass` varchar(45) NOT NULL COMMENT '图片样式',
  `aliasName` varchar(20) NOT NULL COMMENT '别名 唯一 比如新闻 就用News代替 栏目Id不显示在url中',
  `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序 (0-10)',
  PRIMARY KEY (`id`),
  UNIQUE KEY `aliasName_UNIQUE` (`aliasName`),
  UNIQUE KEY `categoryName_UNIQUE` (`categoryName`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='分类表 只支持一级分类 如果需要分多个层次 用标签来协助实现'

用户表:
| t_manager | CREATE TABLE `t_manager` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(25) NOT NULL COMMENT '用户名',
  `password` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8    |

大型博客架构设计 博客管理系统项目介绍_java

详解博客

搭建博客整体目录结构

大型博客架构设计 博客管理系统项目介绍_maven_02

配置SSM框架所需的依赖等

我们使用SSM框架,就必须导入响应的依赖,以下是我们需要的依赖:

<!--  字符编码 -->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <org.springframework.version>4.1.0.RELEASE</org.springframework.version>
    <druid.version>0.2.6</druid.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!-- Spring Start -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${org.springframework.version}</version>
    </dependency>

    <!-- Spring End -->

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>${druid.version}</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.0.5</version>
    </dependency>


    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.2.4</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.2.1</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.3</version>
    </dependency>

  </dependencies>

<!-- 部署服务器所需依赖 -->
	 <plugin>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>9.0.0.v20130308</version>
          <configuration>
            <httpConnector>
              <port>8080</port>
            </httpConnector>
          </configuration>
        </plugin>

我们看到,上面有的依赖中,我们使用了${…},这表示,我们引用了自己所配置的iml文件,所以我们还需要自己配置以下iml文件如下:

<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
      <output url="file://$MODULE_DIR$/target/classes" />
      <output-test url="file://$MODULE_DIR$/target/test-classes" />
      <content url="file://$MODULE_DIR$">
        <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
        <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
        <excludeFolder url="file://$MODULE_DIR$/target" />
      </content>
      <orderEntry type="inheritedJdk" />
      <orderEntry type="sourceFolder" forTests="false" />
      <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" />
      <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-aop:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: aopalliance:aopalliance:1.0" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-aspects:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.8.2" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-beans:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-context:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-expression:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-core:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: commons-logging:commons-logging:1.1.3" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-context-support:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-tx:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-jdbc:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-web:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: org.springframework:spring-webmvc:4.1.0.RELEASE" level="project" />
      <orderEntry type="library" name="Maven: com.alibaba:druid:0.2.6" level="project" />
      <orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.0.5" level="project" />
      <orderEntry type="library" name="Maven: org.mybatis:mybatis:3.2.4" level="project" />
      <orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:1.2.1" level="project" />
      <orderEntry type="library" name="Maven: javax.servlet:jstl:1.2" level="project" />
      <orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:servlet-api:2.5" level="project" />
      <orderEntry type="library" name="Maven: com.google.code.gson:gson:2.3" level="project" />
    </component>

SSM相关的开发

博客项目基于SSM框架,所以我们需要配置Spring、SpringMVC、以及MyBatis。

MyBatis相关开发

1、配置MyBatis的xml文件(可要可不要)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- 根标签 -->
<configuration>

</configuration>

2、开发pojo类
3、创建相关mapper的xml文件
4、创建相关mapper的接口文件

Spring相关开发

1、配置Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd


    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--  注解扫描 -->
    <context:component-scan base-package="com.zyx"/>

    <!--数据源:Druid连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost/blog" />
        <property name="username" value="root" />
        <property name="password" value="woaini" />
    </bean>

    <bean id ="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis.xml"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

    <!--<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">-->
        <!--<property name="sqlSessionFactory" ref="sqlSessionFactory"/>-->
        <!--<property name="mapperInterface" value="com.zyx.dao.UserMapper"/>-->
  <!--</bean>-->

    <!-- 自动扫描指定包内接口为org.mybatis.spring.mapper4.MapperFactoryBean -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- mapper接口包 -->
    <property name="basePackage" value="com.zyx.dao" />
    <!-- mapper接口需要用到sqlSessionFactory 如果上下文环境只有一个数据源 则不需要配置 -->
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
</beans>

在Spring配置文件中,配置要用到的数据源、以及Spring注解扫描的包路径。还有我们要用到的mapper接口文件

SpringMVC相关开发

前端控制器配置在web.xml中
处理器映射器配置在springMVC的配置文件中

<!--  springMVC配置文件 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">

    <!--  注解扫描controller -->
    <context:component-scan base-package="com.zyx.controller"/>

    <!--  配置处理器映射器和处理器适配器 -->
    <mvc:annotation-driven/>

    <!--  配置视图解析器、 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

Web.xml的配置
由于我们要使用到jsp这些静态资源,所以我们要在web.xml文件中配置静态资源的加载。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>

  <!--字符集编码配置-->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- 监听spring -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springconfig.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- 配置前端控制器 -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--  配置springmvc -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!--静态资源的加载-->
  <servlet>
    <servlet-name>default</servlet-name>
    <!--jetty容器-->
    <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
    <!--Tomcat容器-->
    <!--<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>-->
    <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!-- 配置静态资源 -->
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.woff2</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.woff3</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.ttf</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.woff</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.map</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
</web-app>

项目开发

一、登录界面

1、效果展示:

大型博客架构设计 博客管理系统项目介绍_maven_03

2、前端

前端login.jsp页面

我们只关注登录成功跳转到的url和表单数据提交方式

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>

<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="renderer" content="webkit">
    <title>后台  - 登录</title>
    <link href="<%=basePath%>css/bootstrap.min.css"  rel="stylesheet">
    <link href="<%=basePath%>font-awesome/css/font-awesome.css"  rel="stylesheet">
    <link href="<%=basePath%>css/animate.css"  rel="stylesheet">
    <link href="<%=basePath%>css/style.css"  rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="<%=basePath%>js/flavr/flavr/css/animate.css" />
    <link rel="stylesheet" type="text/css" href="<%=basePath%>js/flavr/flavr/css/flavr.css" />
    <link href="<%=basePath%>css/plugins/toastr/toastr.min.css" rel="stylesheet">

    <script type="text/javascript">
        // 登录
        function login(){
            var loginId = $("#loginId").val();
            var password = $("#password").val();
            if(isEmpty(loginId)){
                toastr.error("账户不能为空");
                return false;
            }

            if(isEmpty(password)){
                toastr.error("密码不能为空");
                return false;
            }
            // 将表单数据以jason数据格式提交给checklogin,检验登录。
            $.ajax({
                url : "checklogin",
                data: $("#form").serialize(),
                method : "post",
                dataType : "json",
                success : function(data) {
                    if (data.resultCode == 'success') {
                    // 如果登陆成功,直接定位到../article/addarticle这个url上。
                        window.location.href = "../article/addarticle";
                    }else{
                        toastr.error(data.errorInfo);
                        return false;
                    }
                }
            })
        }
    </script>
    <style>
        .loginscreen.middle-box{padding-top:260px;}
    </style>
</head>

<body class="gray-bg">

<div class="middle-box text-center loginscreen  animated fadeInDown">
    <div>
        <div>
            <h1 class="logo-img"></h1>
        </div>

        <%--通过form表单将登录用户名/密码提交后台--%>
        <form id="form" class="m-t" role="form" >
            <div class="form-group"><h2 >博客系统登录后台</h2></div>
            <div class="form-group">
                <input type="text" name="name" id="loginId" class="form-control" placeholder="用户名">
            </div>
            <div class="form-group">
                <input type="password" name="passwd" id="password" class="form-control" placeholder="密码">
            </div>
            <button type="button" class="btn btn-primary block full-width m-b" onclick="login()">登 录</button>

        </form>
    </div>
</div>

<script src="<%=basePath%>js/jquery-2.1.1.min.js" ></script>
<script src="<%=basePath%>js/bootstrap.min.js" ></script>
<script type="text/javascript" src="<%=basePath%>js/flavr/flavr/js/flavr.min.js"></script>
<script type="text/javascript" src="<%=basePath%>js/flavr/base.js"></script>
<script src="<%=basePath%>js/validation.js"></script>
<script src="<%=basePath%>js/plugins/toastr/toastr.min.js"></script>
</body>

</html>

后端

我们通过上面可以看到,前端将数据以json的形式传递给cheicklogin,所以我们在Controller层上要有一个对应的方法,用于检验登录的用户名和密码是否正确,以及登陆成功后,跳转到article/addarticle,我们也要给这个url对应一个方法。

1、dao层开发

既然要判断我们登录的用户名是否正确,就少不了我们要去数据库拿到对应的username和password。此时需要dao层。

public interface UserMapper {
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "username",property = "name"),
            @Result(column = "password",property = "pwd")
    })
    @Select("SELECT * FROM t_manager WHERE username = #{name} AND password = #{pwd}")
    public User selectUserByNameAndPwd(@Param("name") String name,@Param("pwd") String pwd);
}
2、Service层开发
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User selectUserByNameAndPwd(String name,String pwd){
        return userMapper.selectUserByNameAndPwd(name,pwd);
    }
}
3、Controller层开发
@Controller
public class UserController {
    @Autowired
    private UserService userService;
	
	//输入网址localhosy:8080/login 就能找到该方法。
	// 该方法返回一个jsp页面,使得前端可以显示登录界面
    @RequestMapping("/login")
    public ModelAndView login(){
        ModelAndView mav = new ModelAndView();
        mav.setViewName("user/login");
        return mav;
    }

// 验证登录
    @RequestMapping("/checklogin")
    @ResponseBody
    public Result checkLogin(String name, String passwd, HttpSession session){
        User user = userService.selectUserByNameAndPwd(name, passwd);
        if (user!=null){
            // 将得到的user保存到session对象中。
            session.setAttribute("loginInfo",user);
            return new Result("success","登录成功");
        }else{
            return new Result("fail","登录失败");
        }
    }

}

存在的问题

我们希望,只有登陆了才可以访问我们的文章列表,而不是所有情况都能访问文章列表,所以,这个时候,我们就要进行过滤操作。上树的HttpSession对象,将我们的user信息保存到缓存中。当我们输入网址进入添加文章的界面时,我们就要根据我们的session对象中的信息,判断是否已经登录,如果登录,则可以正常显示添加文章界面,如果没有登陆,则跳转到登录界面。所以,我们新增文章界面需要加一些代码。这个在下部分涉及到。

二、新增文章页面展示

前端

1、需要用到的jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8" import="java.util.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ page isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="renderer" content="webkit">
    <link href="<%=basePath%>css/bootstrap.min.css"  rel="stylesheet">
    <link href="<%=basePath%>font-awesome/css/font-awesome.css"  rel="stylesheet">
    <!-- Data Tables -->
    <link href="<%=basePath%>css/plugins/dataTables/dataTables.bootstrap.css"  rel="stylesheet">
    <link href="<%=basePath%>css/animate.css" rel="stylesheet">
    <link href="<%=basePath%>css/style.css" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="<%=basePath%>js/flavr/flavr/css/animate.css" />
    <link rel="stylesheet" type="text/css" href="<%=basePath%>js/flavr/flavr/css/flavr.css" />
    <link href="<%=basePath%>css/plugins/datapicker/datepicker3.css" rel="stylesheet">
    <link href="<%=basePath%>css/plugins/chosen/chosen.css" rel="stylesheet">

    <style>
        .input-upload{ position: relative;}
        .input-upload input[type="file"]{ position: absolute; left: 0px; top: 0px; width: 72px; height: 35px; opacity:.0;filter:alpha(opacity=00);}
    </style>
    <title>新增博客</title>
</head>
<body>
<div id="wrapper">

    <div id="page-wrapper" class="gray-bg dashbard-1">
        <%--<div class="row wrapper border-bottom white-bg page-heading">--%>

        <%--</div>--%>


        <div class="wrapper wrapper-content animated fadeInRight">

            <div class="row">
                <div class="col-lg-12">
                    <div class="ibox float-e-margins">
                        <div class="ibox-content">
                            <form method="get" class="form-horizontal">
                                <div class="form-group">
                                    <label class="col-sm-2 control-label">类别:</label>
                                    <div class="col-sm-4">
                                        <select class="form-control m-b" id="categoryId">
                                            <option value="-1">无</option>
                                            <c:forEach items="${categoryList}" var="category">
                                                <option value="${category.id}">${category.categoryName}</option>
                                            </c:forEach>
                                        </select>
                                    </div>
                                </div>

                                <div class="form-group">
                                    <label class="col-sm-2 control-label">博客标题</label>
                                    <div class="col-sm-10">
                                        <input type="text" id="title" class="form-control" placeholder="请填写博客名">
                                    </div>
                                </div>
                                <div class="hr-line-dashed"></div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label">博客内容:</label>
                                    <div class="col-sm-10">
                                        <script id="editor" type="text/plain"></script>
                                    </div>
                                </div>
                                <div class="hr-line-dashed"></div>

                                <div class="form-group">
                                    <label class="col-sm-2 control-label">标签:</label>
                                    <div class="col-sm-10">
                                        <select data-placeholder="请选择标签" class="chosen-select" multiple style="width:450px;" tabindex="5">
                                            <c:forEach items="${tagList}" var="tag">
                                                <option value="${tag.id}" hassubinfo="true">${tag.tagName}</option>
                                            </c:forEach>
                                        </select>
                                    </div>
                                </div>

                                <div class="form-group">
                                    <div class="col-sm-4 col-sm-offset-2">
                                        <button class="btn btn-primary" type="button" οnclick="saveArticle()">保存</button>
                                        <button class="btn btn-white" type="button" οnclick="cancelSaveArticle()">取消</button>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>

        </div>

    </div>
</div>

</div>

<!-- Mainly scripts -->
<script src="<%=basePath%>js/jquery-2.1.1.min.js"></script>
<script src="<%=basePath%>js/bootstrap.min.js"></script>
<script src="<%=basePath%>js/plugins/metisMenu/jquery.metisMenu.js"></script>
<script src="<%=basePath%>js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
<script src="<%=basePath%>js/hplus.js"></script>
<script src="<%=basePath%>js/plugins/pace/pace.min.js"></script>
<script src="<%=basePath%>js/validation.js"></script>
<%--自定义js--%>
<script src="<%=basePath%>js/article/add_article.js"></script>
<script type="text/javascript" src="<%=basePath%>js/flavr/flavr/js/flavr.min.js"></script>
<script type="text/javascript" src="<%=basePath%>js/flavr/base.js"></script>
<script type="text/javascript" src="<%=basePath%>js/zTree_v3/js/jquery.ztree.all-3.5.js"></script>
<script src="<%=basePath%>js/plugins/datapicker/bootstrap-datepicker.js"></script>
<script type="text/javascript" src="<%=basePath%>js/ueditor1_4_3/ueditor.config.js"></script>
<script type="text/javascript" src="<%=basePath%>js/ueditor1_4_3/ueditor.all.js"></script>
<script type="text/javascript" charset="utf-8" src="<%=basePath%>js/ueditor1_4_3/lang/zh-cn/zh-cn.js"></script>
<script type="text/javascript" src="<%=basePath%>js/ajaxfileupload.js"></script>
<script src="<%=basePath%>js/plugins/chosen/chosen.jquery.js"></script>
<script type="text/javascript" src="<%=basePath%>js/imageUtils.js"></script>

<script type="text/javascript">
    $(document).ready(function () {
        var UEDITOR_HOME_URL = "/js/ueditor1_4_3/";
        var ue = UE.getEditor('editor');
    })

    $(".chosen-select").chosen({
        max_selected_options:5,
        no_results_text:"û���ҵ�",
        allow_single_deselect:true
    });

</script>
</body>
</html>

2、用到的js文件:

add_article.js文件
// 保存文章
function saveArticle(){
    var param = {};

    // 收集参数 校验
    //$("#categoryId").val()
    var categoryId = $("#categoryId").val();
    if(categoryId == '-1'){
    	autoCloseAlert("请选择栏目",500);
    	return false;
    }
    param["categoryId"] = categoryId;
    
    var title = $("#title").val();
    if(isEmpty(title)){
    	autoCloseAlert("请输入标题",500);
    	return false;
    }
    param["title"] = title;
    
    var arr = [];
    arr.push(UE.getEditor('editor').getContent());
    var content = arr.join("\n");
    
    // 简介
    var description = UE.getEditor('editor').getContentTxt().substring(0,500);
    
    // 标签
    var tagId = $(".chosen-select").val();
    // alert(tagId);
    if(!isEmpty(tagId)){
    	var ids = (tagId+"").split("\,");
    	var tagArray = [];
    	for(var i=0;i<ids.length;i++){
    		tagObj = {"id":ids[i]};
    		// alert(tagObj.id);
    		tagArray.push(tagObj);
    	}
    	param["tagList"] = tagArray;
    	console.info(tagArray);
    }else{
    	autoCloseAlert("请输入标签",500);
    	return false;
    }
    // alert('param='+encodeURI(encodeURI(JSON.stringify(param))));
    // 保存文章
    $.ajax({
        type : "POST",
        url : '../article/add',
        data : 'param='+encodeURI(encodeURI(JSON.stringify(param)))+"&content="+encodeURI(encodeURI(content)).replace(/\&/g, "%26").replace(/\+/g, "%2B")+"&description="+encodeURI(encodeURI(description)),
        success  : function(data) {
        	if(data.resultCode != 'success'){
        		autoCloseAlert(data.errorInfo,1000);
				return false;
			}else{
				// 调到列表页
				window.location.href = "../article/detail";
			}
		}
    });
}

function cancelSaveArticle(){
	window.location.href = "../article/list";
}

新增文章页面后端开发

涉及到的pojo类这里不再一一展示。

我们提取jsp页面中的关键信息:
                          script src="<%=basePath%>js/article/add_article.js">
                          通过add_article.js文件,将我们输入的信息提供给后台去处理。
                          我们要知道,jsp页面上显示的数据,都是我们从数据库里拿来的,不是jsp页面自带的。比如jsp页面中的类别可选项有:篮球、足球等。这些数据是从数据库里拿的,所以我们先要从数据里拿到这些数据,然后讲这些数据传给jsp页面,让其在jsp页面显示出来。

1、dao层开发
// 其对应的dao层:
public interface CategoryMapper {
    @Select("SELECT * FROM t_category")
    public List<Category> getAllCategories();
}

public interface TagMapper {
    @Select("SELECT * FROM t_tag")
    public List<Tag> getAllTags();
}
2、Service层开发
// 其中service层对应的getAllTags()、及getAllCategoryies():
@Service
public class GetAllCategoriesService {
    @Autowired
    private CategoryMapper categoryMapper;

    public List<Category> getAllCategories(){
        return categoryMapper.getAllCategories();
    }
    
@Service
public class GetAllTagsService {
    @Autowired
    private TagMapper tagMapper;

    public List<Tag> getAllTags(){
        return tagMapper.getAllTags();
    }
}
3、Controller层开发

所以我们在controller层才有了showAddArticleView方法

// 展示添加博客的界面
    @RequestMapping("/addarticle")
    public String showAddArticleView(Model model, HttpSession session) {
        // 获取我们的缓存信息,判断用户是否已经登录
        User user = (User)session.getAttribute("loginInfo");

        if (user!=null) {
            List<Tag> tags = getAllTagsService.getAllTags();
            List<Category> categories = getAllCategoriesService.getAllCategories();
            model.addAttribute("tagList",tags);
            model.addAttribute("categoryList",categories);

            return "article/addArticle";

        }else{
            return "redirect:../login";
        }
    }

这样我们才能正常的显示jsp页面中所要的数据。

即如下图: 类别的可选项,是我们从数据库获取的

大型博客架构设计 博客管理系统项目介绍_maven_04

三、文章保存同步到数据库(操作文章使用Article类)

在上面的add_article.js文件中,我们可以看到,前端页面在往后台传递数据的时候,使用到了param参数。并且通过了加密的形式进行数据的传输。所以,我们在后台获取数据的时候要解密以及获取param所包含的内容。

要考虑的问题

           1、在数据库中,我们将content字段设置为了blob类型,但是在我们的bean中Article类中,我们将content设置成了String类型。这样会导致,在数据存入数据库、以及数据库取出数据输出给前端的时候,会出现乱码问题,此时,我们需要在ArticleMapper的配置文件中 使用resultMap标签指定类型转换。
           2、当我们向数据库加入信息时,不要忘了,我们还有一个t_article_tag表。这个表是用来存储文章id和标签id的对应关系的。所以当我们向Article表中添加信息时,还需要将我们的文章Id存储到t_article_tag表中,由于我们Article表中的id在Article表中是以主键、自增的方式设定的,所以,我们一开始获取到的Article对象是不包含id属性的。如何在向Article表中添加信息的同时获取文章id呢?
           这就要用来我们,mybatis中主键自增的获取了。**我们需要使用注解@Options(useGeneratedKeys=true, keyProperty=“XXX”, keyColumn=“XXX”)**注解来获取主键自增。该注解就表示,获取我们自增长的主键赋值给我们新插入对象的属性。
           其中useGenerateKeys=true表示使用自增主键。keyProperty表示对应实体类的属性keyColumn表示数据库中的字段名。
           这样一来,我们就可以实现在添加文章信息的同时,获取到文章的id,然后再通过sql语句,将我们的文章id和标签id存储到t_article_tag表中。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.zyx.bean.Article">
    <resultMap id="articleMapper" type="com.zyx.dao.ArticleMapper">
        <result column="id" property="id"/>
        <result column="categoryId" property="categoryId"/>
        <result column="title" property="title"/>
        <result column="decription" property="description"/>
        <result column="author" property="author"/>
        <result column="createTime" property="createTime"/>
        <result column="showCount" property="showCount"/>
       	<!--  解决blob类型转换 -->
        <result column="content" property="content" typeHandler="com.zyx.util.ConvertBlobTypeHandler"/>
    </resultMap>

</mapper>

文章同步的后端开发

1、开发dao层
@Insert("INSERT INTO t_article (categoryId,title,content,decription,statue,author,createTime) VALUES(#{categoryId},#{title},#{content},#{description},#{statue},#{author},#{createTime})" )
      @Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")
    public int addArticle(Article article);
2、开发Service层
public int addArticle(Article article){
        // 将数据插入到数据库,然后让数据库返回一个Article对象
        // 拿到这个对象,就能获取id和tag_id,将这两个 又插入到 t_article_tag这个表中。
        articleMapper.addArticle(article);
        Integer articleId = article.getId();
        List<Tag> tagList = article.getTagList();
        System.out.println(tagList);
        for (Tag t:tagList){
            Integer tagId = t.getId();
            articleMapper.addArticle_tag(articleId,tagId);
        }
        return 1;
    }
3、开发controller层
// 添加文章
    @RequestMapping("/add")
    public Result addArticle(String param, String content, String description){
        int i = 0;
        try {
            // 解码
            String param1 = URLDecoder.decode(param, "utf-8");
            String content1 = URLDecoder.decode(content,"utf-8");
            String description1 = URLDecoder.decode(description,"utf-8");
//            System.out.println(param1);
//            System.out.println(content1);
//            System.out.println(description1);

            //将JSON数据,转换为我们指定的类
            Article article = JsonUtil.fromJson(param1, Article.class);
            // 将前端输入的内容传入给后台
            article.setContent(content1);
            // 将前端输入的名字,传入给后台,由于我们我还没进行登录操作,这块暂给定一个常量
            article.setAuthor("张XX");
            // 描述
            article.setDescription(description1);
            // 时间
            article.setCreateTime(new Date());
            // 状态
            article.setStatue(0);
            System.out.println(article);
            i = addArticleService.addArticle(article);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (i>0){
            return new Result("success","处理成功");
        }else{
            return new Result("fail","处理失败");
        }

    }

效果展示:

大型博客架构设计 博客管理系统项目介绍_ssm_05


数据库展示:

大型博客架构设计 博客管理系统项目介绍_java_06

四、文章列表显示

展示效果页面

大型博客架构设计 博客管理系统项目介绍_spring_07

前端

1、jsp页面

首页框架:index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%@ page isELIgnored="false" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!--  首页框架页面 -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <link rel="stylesheet" id="main-css" href="<%=basePath%>css/demo/style.css" type="text/css" media="all">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=11,IE=10,IE=9,IE=8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
    <meta name="baidu-site-verification" content="emEdenaBVA">
    <meta http-equiv="Cache-Control" content="no-siteapp">
    <title>博客系统</title>


</head>

<body id="contain" class="home blog ui-c3">
<section class="container">
    <header class="header">
        <div class="logo_right"><span class="glyphicon glyphicon-search degfy_search"></span></div>
        <div class="logo_left"></div>
        <h1 class="logo"><a href="">博客系统</a></h1>
        <ul class="nav">

            <li class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-61">
                <a href="..home/index">
                    <span class="glyphicon glyphicon-home"></span>首页
                </a>
            </li>

            <%--类别--%><!--  loadPage -> loadPage1 -->
            <c:forEach items="${categoryList}" var="category">
                <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-61">
                    <!--a href= =basePath%>loadPage/ -->
                    <a href="<%=basePath%>home/${category.id}"></span>${category.categoryName}
                    </a></li>
            </c:forEach>

        </ul>
        <div class="widget_head"></div>
    </header>
    <div class="content-wrap">
        <div class="content" id="content">
            <h3 class="title"><strong>最新发布</strong></h3>
            <input type="hidden" id="categoryId" value="-1"/>
        </div>
    </div>
    <aside class="sidebar">

        <div class="widget widget_tags">
            <h3 class="title"><strong>热门标签</strong></h3>
            <ul class="widget_tags_inner">
                <c:forEach items="${tagList}" var="tag">
                    <li><a title="" href="javascript:;" >${tag.tagName}</a></li>
                </c:forEach>
            </ul>
        </div>
    </aside>

</section>

<%--从本项目的指定路径获取js文件--%>
<script type="text/javascript" src="<%=basePath%>js/jquery-2.1.1.min.js"></script>
<%--自定义js--%>
<script type="text/javascript" src="<%=basePath%>js/article/article_list.js"></script>

</body>

</html>

</body>
</html>

博客列表页面:articlepager.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    String basePath1 = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/";
%>

<!--  博客列表页面  -->

<c:forEach items="${articleList}" var="article">
    <article class="excerpt excerpt-one">
        <header>
            <!--  loadPage1 ->loadPage  -->
            <a class="cat label label-important" href="<%=basePath%>home/${article.categoryId}" data-original-title="" title="">${article.categoryName}
                <i class="label-arrow"></i>
            </a>
            <h2><a target="_blank" href="<%=basePath1%>article/${article.id}" title="${article.title}">${article.title}</a></h2>
        </header>

        <p class="text-muted time">作者:${article.author}     发布于 ${article.time}</p>

        <p class="focus">
            <a target="_blank" href="<%=basePath1%>article/${article.id}" class="thumbnail">
                <span class="item">
                    <span class="thumb-span">
                    </span>
                </span>
            </a>
        </p>
        <p class="note">
                   ${fn:substring(article.description,0,20)}...
        </p>
        <p class="text-muted views">
            <span class="post-views">阅读(${article.showCount})</span>
            <span class="post-tags">标签:
        <c:forEach items="${article.tagList}" var="tag" varStatus="status">
            <a href="javascript:void(0)"  rel="tag" data-original-title="" title="">${tag.tagName}</a>
            <c:if test="${fn:length(article.tagList) > (status.index+1)}">
                /
            </c:if>
        </c:forEach>
    </span>
        </p>

    </article>

</c:forEach>

按照类别访问:articlepager1.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ page isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!--  按类别访问页面  -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head>
    <link rel="stylesheet" id="main-css" href="<%=basePath%>css/demo/style.css" type="text/css" media="all" />
    <meta http-equiv="X-UA-Compatible" content="IE=11,IE=10,IE=9,IE=8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0" />
    <meta name="baidu-site-verification" content="emEdenaBVA" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <title>${ca.categoryName} - 博客系统</title>


</head>

<body id="contain" class="home blog ui-c3">
<section class="container">
    <header class="header">
        <div class="logo_right"><span class="glyphicon glyphicon-search degfy_search"></span></div>
        <div class="logo_left"></div>
        <h1 class="logo"><a href="">博客系统</a></h1>
        <ul class="nav">

            <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-home menu-item-61">
                <a href="<%=basePath %>">
                    <span class="glyphicon glyphicon-home"></span>首页
                </a>
            </li>
            <c:forEach items="${categoryList}" var="category">
                <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-61
        <c:if test="${ca.id == category.id}">
            current_page_item
        </c:if>
    ">
                    <a href="<%=basePath%>home/${category.id}">${category.categoryName}
                    </a></li>
            </c:forEach>

        </ul>       <div class="widget_head">
    </div>
    </header>
    <div class="content-wrap">
        <div class="content" id="content">
            <h3 class="title"><strong>${ca.categoryName}</strong></h3>
            <input type="hidden" id="categoryId" value="${ca.id}"/>

        </div>
    </div>
    <aside class="sidebar">
        <div class="widget widget_tags">
            <h3 class="title"><strong>热门标签</strong></h3>
            <ul class="widget_tags_inner">
                <c:forEach items="${tagList}" var="tag">
                    <li><a title="">${tag.tagName}</a></li>
                </c:forEach>
            </ul>
        </div>

        </div>
    </aside>
</section>

<div id="back_hidden"></div>
<script type="text/javascript" src="<%=basePath%>js/jquery-2.1.1.min.js"></script>
<%--自定义的路径--%>
<script type="text/javascript" src="<%=basePath%>js/category/article_list.js"></script>
</body>

</html>
2、相应的js文件:

category/article_list.js:

$(function(){
	loadNextPage(99999999999);

	$(window).scroll(function(){
		checkload();
	});
	
//建立加载判断函数
function checkload(){
	totalheight = parseFloat($(window).height()) + parseFloat($(window).scrollTop());
    if ($(document).height() <= totalheight) {
    	if($("#lastId").val() != 'undefined' && $("#lastId").val() != null && $("#lastId").val() != ''){
        	loadNextPage($("#lastId").val());
    	}
    }
}

//创建ajax加载函数,并设置变量C,用于输入调用的页面频道,请根据实际情况判断使用,非必要。
function loadNextPage(lastId){
		$.ajax({
									url : '../home/detailCategory' +'/'+ $("#categoryId").val(),
									type : "get",
									success : function(data) {
										if($.trim(data) != ''){
											$("#lastId").remove();
											$("#content").append(data);
											$('img').lazyload();
										}
									}
		});	
}  
});  

function goTag(tagName){
	window.location.href = "http://coriger.com/tag/"+encodeURI(encodeURI(tagName))
}

article/article_list.js:

$(function () {
    loadNextPage(99999999999);


//创建ajax加载函数,并设置变量C,用于输入调用的页面频道,请根据实际情况判断使用,非必要。
    function loadNextPage(lastId) {
        $.ajax({
            url: 'loadPageAll',//   /home/loadPageAll/-1/
            type: "get",
            success: function (data) {
                if ($.trim(data) != '') {
                    $("#lastId").remove();
                    $("#content").append(data);
                    $('img').lazyload();
                }
            }
        });
    }
});

后端

1、dao层开发
//通过文章id查询标签
    @Select("SELECT tt.* FROM t_tag tt, t_article_tag tat WHERE tt.id = tat.tagId AND tat.articleId = #{articleId}")
    public List<Tag> selectTagsByArticleId(Integer articleId);
 
    //通过id查找文章
    @Select("SELECT * FROM t_article ta,t_category tc WHERE ta.categoryId = tc.id AND ta.id = #{id}")
    public Article selectArticleById(Integer id);
    

    // 查询所有文章信息
    @Select("SELECT * FROM t_article ta, t_category tc WHERE ta.categoryId = tc.id ORDER BY createTime DESC")
    public List<Article> selectAllArticles();

    // 通过类别id查找文章
    @Select("SELECT * FROM t_article ta,t_category tc WHERE ta.categoryId = tc.id AND ta.categoryId = #{categoryId}")

    public List<Article> selectArticlesByCategoryId(Integer categoryId);

    // 通过文章id查找文章,使浏览量自增
    @Update("UPDATE t_article SET showCount = #{showCount} WHERE id = #{id} ")
    public void updateShowCount(@Param("showCount") Integer showCount,@Param("id") Integer id);

    //通过文章id查询标签
    @Select("SELECT tt.* FROM t_tag tt, t_article_tag tat WHERE tt.id = tat.tagId AND tat.articleId = #{articleId}")
    public List<Tag> selectTagsByArticleId(Integer articleId);
2、Service层开发
public Article selectArticleById(Integer id){
        Article a =  articleMapper.selectArticleById(id);
        List<Tag> tags = articleTagMapper.selectTagsByArticleId(id);
        a.setTagList(tags);
        return a;
    }

    //获取所有的文章信息
    public List<Article> getAllArticles(){
        List<Article> artciles = articleMapper.selectAllArticles();
        return handler(artciles);
    }
    // 将数据库日期格式转换为"yyyy年MM月DD日 HH时mm分ss秒"
    // 获取文章的标签信息
    private List<Article> handler(List<Article> articles){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年-MM月-DD日 HH时mm分ss秒");
        for (Article a: articles) {
            // 获取文章的标签信息
            List<Tag> tags = articleTagMapper.selectTagsByArticleId(a.getId());
            a.setTagList(tags);
            // 日期格式转换
            String time = sdf.format(a.getCreateTime());
            a.setTime(time);
        }
        return articles;
    }

    //通过categoryId获取文章
    public List<Article> getArticlesByCategoryId(Integer categoryId){
        List<Article> articles = articleMapper.selectArticlesByCategoryId(categoryId);
        List<Article> a = handler(articles);
        return a;
    }

    // 修改阅读量
    public void updateShowCount(Integer showCount,Integer articleId){
         articleMapper.updateShowCount(showCount,articleId);
    }
	
    public List<Tag> selectTagsByArticleId(Integer articleId){
        return articleTagMapper.selectTagsByArticleId(articleId);
    }
Controller层开发
// 跳转到详情页面
    // 通过url中的id拿到指定文章的id,然后去数据库查询信息
    @RequestMapping("/{id}")
    public String showDetail(Model model,@PathVariable("id") Integer id) {
        System.out.println("******");
        Article article = addArticleService.selectArticleById(id);
        System.out.println(article);
        // 浏览量
        Integer showCount = article.getShowCount();
        addArticleService.updateShowCount(showCount+1,id);
        model.addAttribute("article",article);
        return "article/articleDetail";
    }
@Controller
@RequestMapping("/home")
public class HomeController {
    @Autowired
    private GetAllTagsService getAllTagsService;
    @Autowired
    private GetAllCategoriesService getAllCategoriesService;
    @Autowired
    private AddArticleService addArticleService;


    // 显示首页框架
    @RequestMapping("/index")
    public String showIndex(Model model){
        List<Category> allCategories = getAllCategoriesService.getAllCategories();
        List<Tag> tagList = getAllTagsService.getAllTags();
        model.addAttribute("categoryList",allCategories);
        model.addAttribute("tagList",tagList);
        return "home/index";
    }

    // 显示首页具体信息
    @RequestMapping("/loadPageAll")
    public String showDetailIndex(Model model){
        List<Article> articleList = addArticleService.getAllArticles();

        model.addAttribute("articleList",articleList);
        return "home/articlepager";
    }

    // index.jsp页面中,通过点击类别,跳转到指定类别的文章列表
    @RequestMapping("/{categoryId}")
    public String showCategoryArticles(@PathVariable("categoryId")Integer categoryId, Model model){
        List<Tag> tagList = getAllTagsService.getAllTags();
        List<Category> allCategories = getAllCategoriesService.getAllCategories();
        Category ca = getAllCategoriesService.getCategoryByCategoryId(categoryId);
        model.addAttribute("tagList",tagList);
        model.addAttribute("categoryList",allCategories);
        model.addAttribute("ca",ca);
        return "home/articlepager1";
    }

    //加载包含指定类别的文章列表
    // 即加载类别id= categoryId的文章
    @RequestMapping("/detailCategory/{categoryId}")
    public String showDetailCategoryArticles(@PathVariable("categoryId")Integer categoryId,Model model){
        List<Article> articles = addArticleService.getArticlesByCategoryId(categoryId);
        model.addAttribute("articleList",articles);
        return "home/articlepager";
    }
}

需要考虑的问题

        1、我们显示的内容中,包含了类别信息、热门标签信息、以及文章主体列表的相关信息:包括文章作者、文章浏览量、文章标签、文章类别等。但是我们的Article表中,关于类别的信息只存在categoryId,而对于标签的信息,压根就没有,等于说,我们如果只查询Article表得到的信息,是不满足于我们页面所要展示的信息的。
至少我们需要拿到类别名称、标签名称。
        2、基于上面的情况,我们就要进行表与表之间的联合查询。首先联合查询t_article表和t_category表,拿到对应的categoryName。
        3、然后联合查询t_article表和t_tag表,拿到对应的标签信息。
        4、此时,我们拿到的Article对象中就包含标签名和类别名等信息。
        5、我们老生常谈的数据库时间类型与我们Java的时间类型转换问题,通过SimpleDateFormat类型进行日期格式的转换。
        6、对于浏览量的问题,我们的理想状况是,每当我们点击一次文章,它的浏览量会加1。我们在显示文章详情的时候,后台会根据文章id找到对应的文章对象article,此时,我们就可以通过拿到article的showCount,使其自增1,然后将自增后的showCount存入到数据库中,这样就能达到浏览量自增1的效果。