文章目录
- 前言
- 一、框架介绍
- 1.1、Spring
- 1.2、SpringMVC
- 1.3、MyBatis
- 1.4、SSM整合
- 二、开发环境
- 三、系统功能
- 3.1 文章列表
- 3.2 点赞评论
- 3.3 在线问答
- 3.4 提问题
- 3.5 后台管理员主界面
- 3.6 文章列表管理
- 3.7 问答列表管理
- 3.8 全站消息发送
- 四、部分代码展示
- 4.1.login.jsp
- 4.2 点赞记录
- 4.2 .1 Controller
- 4.2.2 Service
- 4.2.3 ServiceImpl
- 4.2.4 dao
- 4.2.5 UserMapper
- 五 、框架其他配置
- 5.1 数据库配置
- 5.2、配置spring-mvc.xml
- 5.3 Log4j的配置
- 5.4 数据库表结构
前言
最近正好在带徒弟做项目,也有很多网友再问,能否个共享一些框架,所以整理了下 把最近部署上线的一套学Spring+SpringMVC+MyBatis的博客问答系统框架分享给各位网友 希望给各位大学僧,网友一些帮助,我是一个乐于分享的人,大家点赞关注哈
一、框架介绍
1.1、Spring
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,
由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
它是为了解决企业应用开发的复杂性而创建的。
Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。
从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架
1.2、SpringMVC
Spring MVC属于SpringFrameWork的后续产品,
已经融合在Spring Web Flow里面。
Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,
这种分离让它们更容易进行定制。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CO5gDO1MWOhdDO3kDZwcTNzYzX1MTMxYDM1IzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
1.3、MyBatis
MyBatis 本是apache的一个开源项目iBatis,
2010年这个项目由apache software foundation 迁移到了google code,
并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。
iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。
MyBatis 使用简单的 XML或注解用于配置和原始映射,
将接口和 Java 的POJOs(Plain Old Java Objects,
普通的 Java对象)映射成数据库中的记录。
1.4、SSM整合
这次整合我分了2个配置文件,分别是spring-mybatis.xml,
包含spring和mybatis的配置文件,还有个是spring-mvc的配置文件,
此外有2个资源文件:jdbc.propertis和log4j.properties。
完整目录结构如下:
二、开发环境
开发语言:Java
技术:JavaWeb【Servlet】
数据库:MySQL
架构:B/S
源码类型: Web
编译工具:Idea、Eclipse、MyEclipse (选其一)
其他:jdk1.8、Tomcat5.7 、Navicat
使用框架的版本:
Spring 3.2.12 RELEASE
Spring MVC 4.0.2 RELEASE
MyBatis 3.2.6
三、系统功能
3.1 文章列表
3.2 点赞评论
支持重复点赞过滤,防止刷点击率
3.3 在线问答
3.4 提问题
3.5 后台管理员主界面
3.6 文章列表管理
3.7 问答列表管理
3.8 全站消息发送
四、部分代码展示
4.1.login.jsp
<%@ page language="java" cnotallow="text/html; charset=UTF-8"%>
<%@ include file="/base.jsp"%>
<!DOCTYPE html>
<html>
<head>
<!-- Meta -->
<meta charset="utf-8" http-equiv="Content-Type" />
<!-- End of Meta -->
<!-- Page title -->
<title>登录 -${websitemap.web.company}-${websitemap.web.title}</title>
<!-- End of Page title -->
<meta name="author" cnotallow="${websitemap.web.author}" />
<meta name="keywords" cnotallow="${websitemap.web.keywords}" />
<meta name="description" cnotallow="${websitemap.web.description}" />
<link rel="shortcut icon" href="${ctx}/favicon.ico" type="image/x-icon">
<!-- Libraries -->
<link type="text/css" href="${ctx}/static/admin/css/login.css" rel="stylesheet" />
<script type="text/javascript">
function enterSubmit(event) {
var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
if (keyCode == 13) {
$("#loginForm").submit();
return false;
}
}
</script>
</head>
<body>
<div id="container">
<div class="logo">
<a href="javascript:void(0);" notallow="return false;" target="_blank" title="Elearning">
</a>
</div>
</div>
<div class="b-box">
<div id="container">
<div id="box">
<h2>在线博客系统</h2>
<form actinotallow="${ctx}/admin/main/login" method="POST" id="loginForm">
<p class="main">
<label>用户名: </label>
<input name="sysUser.loginName" notallow="enterSubmit(event)" value="${sysUser.loginName}" placeholder="输入用户名" />
<label>密码: </label>
<input type="password" notallow="enterSubmit(event)" name="sysUser.loginPwd" value="${sysUser.loginPwd}" placeholder="输入密码">
</p>
<p class="main">
<label>验证码: </label>
<input name="randomCode" notallow="enterSubmit(event)" placeholder="验证码" style="width: 105px;" maxlength="4"/>
<span class="yzm-pic">
<img src="${ctx}/ran/random" alt="验证码,点击图片更换" notallow="this.src='${ctx}/ran/random?random='+Math.random();" />
</span>
</p>
<p class="space">
<input type="submit" value="登录" class="login" />
<span>${message}</span>
</p>
</form>
</div>
<div class="login-foot">
<span>
Powered By <a target="_blank" href="#" style="color: #666;">IT邦德</a>
</span>
</div>
</div>
</div>
</body>
</html>
4.2 点赞记录
4.2 .1 Controller
/**
* 添加点赞记录
*/
@RequestMapping("/praise/ajax/add")
@ResponseBody
public Object addPraise(HttpServletRequest request,@ModelAttribute("praise")Praise praise){
Map<String,Object> json = new HashMap<String,Object>();
try{
int userId = SingletonLoginUtils.getLoginUserId(request);
if (userId==0) {
json = this.setJson(false, "请先登录", "");
return json;
}
//查询是否点赞 过
praise.setUserId(Long.valueOf(userId));
int praiseCount=praiseService.queryPraiseCount(praise);
if(praiseCount>0){
json = this.setJson(false, "您已赞过", "");
return json;
}
//添加点赞记录
praise.setAddTime(new Date());
praiseService.addPraise(praise);//在service 中
根据点赞目标 type 修改相应的 点赞总数
json = this.setJson(true, "", "");
}catch (Exception e) {
logger.error("PraiseController.addPraise()---error",e);
json = this.setJson(false, "系统错误,请稍后重试", "");
}
return json;
}
4.2.2 Service
public interface PraiseService {
/**
* 添加点赞记录
*/
public Long addPraise(Praise praise);
/**
* 根据条件查询点赞数
*/
public int queryPraiseCount(Praise praise);
}
4.2.3 ServiceImpl
@Override
public Long addPraise(Praise praise) {
//根据点赞目标 type 修改相应的 点赞总数
//点赞类型 1问答点赞 2问答评论点赞
int type=praise.getType();
if(type==1){
Questions questinotallow=questionsService.getQuestionsById(praise.getTargetId());
questions.setPraiseCount(questions.getPraiseCount()+1);
questionsService.updateQuestions(questions);
}else if (type==2) {
QuestionsComment questinotallow=questionsCommentService.getQuestionsCommentById(praise.getTargetId());
questionsComment.setPraiseCount(questionsComment.getPraiseCount()+1);
questionsCommentService.updateQuestionsComment(questionsComment);
}
//点赞类型为3的是文章点赞
if(type==3){
Map<String,String> map = new HashMap<String,String>();
map.put("num","+1");
map.put("type", "praiseCount");
map.put("articleId", praise.getTargetId()+"");
articleService.updateArticleNum(map);
}
//点赞类型为4的是评论点赞
if(type==4){
Map<String,String> map = new HashMap<String,String>();
map.put("num","+1");
map.put("type", "praiseCount");
map.put("commentId", praise.getTargetId()+"");
commentService.updateCommentNum(map);
}
return praiseDao.addPraise(praise);
}
4.2.4 dao
public interface CommentService {
/**
* 分页查询评论
*/
public List<Comment> getCommentByPage(Comment comment,PageEntity page);
/**
* 添加评论
*/
public void addComment(Comment comment);
/**
* 更新评论
*/
public void updateComment(Comment comment);
/**
* 查询评论
*/
public Comment queryComment(Comment comment);
/**
* 查询评论互动
*/
public List<Comment> queryCommentInteraction(Comment comment);
/**
* 更新评论点赞数,回复数等
*/
public void updateCommentNum(Map<String,String> map);
/**
* 删除评论
*/
public void delComment(int commentId);
/**
* 查询评论 list
*/
public List<Comment> queryCommentList(Comment comment);
}
4.2.5 UserMapper
<?xml versinotallow="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="PraiseMapper">
<resultMap type="Praise" id="PraiseResult">
<result property="id" column="ID"/>
<result property="ip" column="USER_ID"/>
<result property="articleId" column="TARGET_ID"/>
<result property="type" column="TYPE"/>
<result property="addTime" column="ADD_TIME"/>
</resultMap>
<sql id="edu_praise_column">
edu_praise.ID,
edu_praise.USER_ID,
edu_praise.TARGET_ID,
edu_praise.TYPE,
edu_praise.ADD_TIME
</sql>
<sql id="edu_praise_property">
#{id},
#{userId},
#{targetId},
#{type},
#{addTime}
</sql>
<!-- 添加 -->
<insert id="addPraise" parameterType="Praise" useGeneratedKeys="true" keyProperty="id" keyColumn="ID">
INSERT INTO edu_praise(<include refid="edu_praise_column"/>) VALUE(<include refid="edu_praise_property"/>)
</insert>
<!-- 查询 -->
<select id="queryPraiseCount" parameterType="Praise" resultType="int">
select IFNULL(count(1),0)
from edu_praise
<where>
<if test="userId!=null and userId!=0">
and edu_praise.USER_ID=#{userId}
</if>
<if test="targetId!=null and targetId!=0">
and edu_praise.TARGET_ID=#{targetId}
</if>
<if test="type!=0">
and edu_praise.TYPE=#{type}
</if>
</where>
</select>
</mapper>
五 、框架其他配置
5.1 数据库配置
project.properties
#数据库主机地址
jdbc.host=localhost
#数据库名
jdbc.database=learn
#用户名
jdbc.username=root
#密码
jdbc.password=root
#项目路径
cnotallow=http://localhost:80
5.2、配置spring-mvc.xml
配置里面的注释也很详细,主要是自动扫描控制器,视图模式,注解的启动这三个。
<?xml versinotallow="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cnotallow="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocatinotallow="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
">
<!-- ①:对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
<context:component-scan base-package="com.inxedu.os"
use-default-filters="false">
<context:include-filter type="annotation"
expressinotallow="org.springframework.stereotype.Controller" />
<context:include-filter type="annotation"
expressinotallow="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:message-converters register-defaults="true">
<!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler />
<!-- ②:拦截器的配置 -->
<mvc:interceptors>
<!-- 后台登录和权限的拦截器配置 -->
<mvc:interceptor>
<mvc:mapping path="/admin/*" />
<mvc:mapping path="/admin/**/*" />
<mvc:exclude-mapping path="/admin/main/login" />
<bean class="com.inxedu.os.common.intercepter.IntercepterAdmin"></bean>
</mvc:interceptor>
<!-- 前台网站配置拦截器配置 -->
<mvc:interceptor>
<mvc:mapping path="/**/*" />
<mvc:exclude-mapping path="/static/**/*" />
<mvc:exclude-mapping path="/*/ajax/**" />
<mvc:exclude-mapping path="/kindeditor/**/*" />
<bean class="com.inxedu.os.common.intercepter.LimitIntercepterForWebsite">
</bean>
</mvc:interceptor>
<!-- 前台用户登录拦截器配置 -->
<mvc:interceptor>
<mvc:mapping path="/uc/*" />
<mvc:mapping path="/uc/**/*" />
<mvc:exclude-mapping path="/uc/tologin" />
<mvc:exclude-mapping path="/uc/getloginUser" />
<mvc:exclude-mapping path="/uc/register" />
<mvc:exclude-mapping path="/uc/createuser" />
<mvc:exclude-mapping path="/uc/login" />
<mvc:exclude-mapping path="/uc/passwordRecovery" />
<mvc:exclude-mapping path="/uc/sendEmail" />
<bean class="com.inxedu.os.common.intercepter.IntercepterWebLogin">
</bean>
</mvc:interceptor>
</mvc:interceptors>
<!-- ③:对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
</bean>
<!-- <mvc:view-controller path="/" view-name="redirect:/index"/> -->
<!-- REST中根据URL后缀自动判定Content-Type及相应的View -->
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<value>
jsnotallow=application/json
xml=application/xml
</value>
</property>
</bean>
<!-- 文件上传限制大小 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- set the max upload size 10MB -->
<property name="maxUploadSize">
<value>5048576000</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
<!-- Spring MVC 内置处理json配置 添加jackson-mapper-asl-1.*.*.jar jackson-core-asl-1.*.*.jar这两个包实现 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<!-- 将Controller抛出的异常转到特定View, 保持SiteMesh的装饰效果 -->
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthorizedException">/WEB-INF/view/common/403</prop>
<prop key="java.lang.Throwable">/common/error</prop>
</props>
</property>
</bean>
</beans>
5.3 Log4j的配置
为了方便调试,一般都会使用日志来输出信息,Log4j是Apache的一个开放源代码项目,
通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,
甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;
我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
log4j.rootLogger=INFO,Console,File
#定义日志输出目的地为控制台
log4j.appender.Cnotallow=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
#可以灵活地指定日志输出格式,下面一行是指定具体的格式
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.Cnotallow=[%c] - %m%n
#文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.File = org.apache.log4j.RollingFileAppender
#指定输出目录
log4j.appender.File.File = logs/ssm.log
#定义文件最大大小
log4j.appender.File.MaxFileSize = 10MB
# 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志
log4j.appender.File.Threshold = ALL
log4j.appender.File.layout = org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c]%m%n