Java项目:在线博客问答系统(java+Springboot+jsp+maven+mysql)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: Java项目:在线博客问答系统(java+Springboot+jsp+maven+mysql)

一、框架介绍



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 分离了控制器、模型对象、分派器以及处理程序对象的角色,
  这种分离让它们更容易进行定制。


4df6fc9484904dc9acc933024f12d60b.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。


完整目录结构如下:

35cee7e0c4fa48e5a3a7ecc7d01c563a.png



二、开发环境



开发语言: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 文章列表


330eb6cccb8449e5b17834fb7536e28a.png


3.2 点赞评论

63b5148083004b80a482fe2bdc4fc064.png



27fce81f4c8a4fbd84ef828dbb31ea98.png

2cc11b43ed0a4ade96a174d73cdeba15.png


3.3 在线问答

727cf6912a8041369dcd991bee4ba7ac.png


3.4 提问题

e133eaf193cb456ca49cef48746f39a1.png


bfa324833df048b983d2bd44a79b80d4.png


3.5 后台管理员主界面

e0a6bcd19c794fe28e2493f9abd866bd.png


3.6 文章列表管理

3818774e06e84a0b975f9088a17f37ba.png



3.7 问答列表管理


815fdcdd8f4141c3aedd5fb472642ed3.png


3.8 全站消息发送


1eeca6cc0c0f4a09ab0a54be6af6e52e.png


四、部分代码展示



4.1.login.jsp


<%@ page language="java" contentType="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" content="${websitemap.web.author}" />
<meta name="keywords" content="${websitemap.web.keywords}" />
<meta name="description" content="${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);" onclick="return false;" target="_blank" title="Elearning">
      </a>
    </div>
  </div>
  <div class="b-box">
    <div id="container">
      <div id="box">
        <h2>在线博客系统</h2>
        <form action="${ctx}/admin/main/login" method="POST" id="loginForm">
          <p class="main">
            <label>用户名: </label>
            <input name="sysUser.loginName" onkeyup="enterSubmit(event)" value="${sysUser.loginName}" placeholder="输入用户名" />
            <label>密码: </label>
            <input type="password" onkeyup="enterSubmit(event)" name="sysUser.loginPwd" value="${sysUser.loginPwd}" placeholder="输入密码">
          </p>
          <p class="main">
            <label>验证码: </label>
            <input name="randomCode" onkeyup="enterSubmit(event)" placeholder="验证码" style="width: 105px;"  maxlength="4"/>
            <span class="yzm-pic">
              <img src="${ctx}/ran/random" alt="验证码,点击图片更换" onclick="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 questions=questionsService.getQuestionsById(praise.getTargetId());
      questions.setPraiseCount(questions.getPraiseCount()+1);
      questionsService.updateQuestions(questions);
    }else if (type==2) {
      QuestionsComment questionsComment=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 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="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
#项目路径
contextPath=http://localhost:80


5.2、配置spring-mvc.xml


配置里面的注释也很详细,主要是自动扫描控制器,视图模式,注解的启动这三个。


<?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/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"
      expression="org.springframework.stereotype.Controller" />
    <context:include-filter type="annotation"
      expression="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>
        json=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.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.Target=System.out  
#可以灵活地指定日志输出格式,下面一行是指定具体的格式  
log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=[%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


5.4 数据库表结构

e1e88fa34dca4148b6097b8da82a9095.png

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
9月前
|
人工智能 运维 Java
SpringBoot+MySQL实现动态定时任务
这是一个基于Spring Boot的动态定时任务Demo,利用spring-context模块实现任务调度功能。服务启动时会扫描数据库中的任务表,将任务添加到调度器中,并通过固定频率运行的ScheduleUpdater任务动态更新任务状态和Cron表达式。核心功能包括任务的新增、删除与Cron调整,支持通过ScheduledFuture对象控制任务执行。项目依赖Spring Boot 2.2.10.RELEASE,使用MySQL存储任务信息,包含任务基类ITask及具体实现(如FooTask),便于用户扩展运维界面以增强灵活性。
331 10
|
7月前
|
Java 区块链 Maven
关于引入maven项目后出现‘parent.relativePath’ of POM错误时的解决方法
关于引入maven项目后出现‘parent.relativePath’ of POM错误时的解决方法
611 3
|
6月前
|
Java jenkins 应用服务中间件
结合Jenkins与Tomcat,实施Maven项目的自动构建和部署流程。
任何项目构建和部署的自动化流程,总离不开对各个环节精细把控与密切配合。涉及到源代码管理、构建工具、持续集成服务器以及最终的运行时环境的协调。通过上述简洁实用的步骤,可以实现Maven项目从源代码到运行状态的无缝过渡,进而提升软件开发的效率与质量。
362 0
|
Java Maven 开发者
maven项目中官方setting.xml文件
`settings.xml` 是 Maven 的配置文件,用于定义用户或全局级别的构建行为。它包含本地仓库路径、网络代理、服务器认证、仓库镜像及构建配置文件等设置,帮助开发者根据环境定制 Maven 行为,提升构建效率与灵活性。
1341 0
|
9月前
|
Java 测试技术 项目管理
【JavaEE】从 0 到 1 掌握 Maven 构建 Java 项目核心技巧 解锁 Java 项目高效管理实用实例
本文从Maven基础概念讲起,涵盖安装配置、核心概念(如POM与依赖管理)及优化技巧。结合Java Web项目实例,演示如何用Maven构建和管理项目,解决常见问题,助你高效掌握这一强大工具,提升Java开发与项目管理能力。适合初学者及进阶开发者学习。资源链接:[点此获取](https://pan.quark.cn/s/14fcf913bae6)。
308 6
|
10月前
|
监控 Java 关系型数据库
Spring Boot整合MySQL主从集群同步延迟解决方案
本文针对电商系统在Spring Boot+MyBatis架构下的典型问题(如大促时订单状态延迟、库存超卖误判及用户信息更新延迟)提出解决方案。核心内容包括动态数据源路由(强制读主库)、大事务拆分优化以及延迟感知补偿机制,配合MySQL参数调优和监控集成,有效将主从延迟控制在1秒内。实际测试表明,在10万QPS场景下,订单查询延迟显著降低,超卖误判率下降98%。
449 5
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
2906 45
|
XML Java 测试技术
从零开始学 Maven:简化 Java 项目的构建与管理
Maven 是一个由 Apache 软件基金会开发的项目管理和构建自动化工具。它主要用在 Java 项目中,但也可以用于其他类型的项目。
743 1
从零开始学 Maven:简化 Java 项目的构建与管理
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
248 5
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
566 1

推荐镜像

更多