文章目录
- 博客管理系统介绍
- 系统实现的功能点
- 博客设计技术
- 前端技术
- 后端技术
- 数据库设计
- 详解博客
- 搭建博客整体目录结构
- 配置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 |
详解博客
搭建博客整体目录结构
配置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、效果展示:
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页面中所要的数据。
即如下图: 类别的可选项,是我们从数据库获取的
三、文章保存同步到数据库(操作文章使用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","处理失败");
}
}
效果展示:
数据库展示:
四、文章列表显示
展示效果页面
前端
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的效果。