首先感谢原作者的倾囊相授!
资源链接:https://github.com/saysky/ForestBlog
本内容仅为个人对整个项目的分析展示,用作学习,如有错误之处还望指点,本项目前端采用LayUI+前端三件套+jQuery实现,本人没有学过LayUI因此不做前端分析,仅展示部分运行部分的页面效果,打算在后续学习使用Vue框架进行实现,再根据分析经验重新对后端进行新的构建,尽力实现自己学习的第一个SSM项目,加油。
分析学习第一个SSM项目:ForestBlog
文章目录
目录基础结构
一、分析pom.xml文件和web.xml文件
1. pox.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.liuyanzhao</groupId>
<artifactId>ForestBlog</artifactId>
<packaging>war</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>ForestBlog Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.19.RELEASE</spring.version>
<jackson-databind-version>2.10.1</jackson-databind-version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<!-- 添加sevlet支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- 添加jsp支持 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 添加jstl支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- 添加spring支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring test支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring mvc支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring 事务管理支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring jdbc操作支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring aop编程支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 添加mybatis支持 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- jdbc驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- 添加阿里巴巴连接池Druid支持 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.16</version>
</dependency>
<!-- 添加logback日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.1</version>
</dependency>
<!-- 添加junit支持 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
<dependency>
<groupId>com.googlecode.rapid-framework</groupId>
<artifactId>rapid-core</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>26.0-jre</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
<!-- hutool工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.1.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-databind-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-databind-version}</version>
</dependency>
</dependencies>
<build>
<resources>
<!-- 编译之后包含xml -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<!-- 编译之后包含xml和properties -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
pom.xml文件使用的依赖:
-
lombok
-
添加sevlet支持
- javax.servlet-api
-
添加jsp支持
- javax.servlet.jsp-api
-
添加jstl支持
- jstl
- standard
-
添加spring支持
- spring-core
- spring-beans
- spring-context
- spring-context-support
- spring-web
-
spring test支持
- spring-test
-
spring mvc支持
- spring-webmvc
-
spring 事务管理支持
- spring-tx
-
spring jdbc操作支持
- spring-jdbc
-
spring aop编程支持
- spring-aop
- spring-aspects
-
添加mybatis支持
- mybatis
- mybatis-spring
-
jdbc驱动包
- mysql-connector-java
-
添加阿里巴巴连接池Druid支持
- druid
-
添加logback日志
- logback-classic
- logback-core
- logback-ext-spring
-
添加junit支持
- junit
-
文件上传
- commons-fileupload
- commons-io
-
jackson
- jackson-databind
- jackson-core
- jackson-annotations
-
rapid-framework是谷歌的一个项目,可以实现jsp网页的继承,也就是书写模板页。
- json
- rapid-core
-
Guava是Google的一个开源Java框架,包含许多Google 内部Java项目依赖的核心类,包括:从集合类型、不可变集合、图结构处理、并发工具、I/O、哈希、缓存等等各个方面的工具。Guava是对Java API的补充,对Java开发中常用功能进行更优雅的实现,Guava库经过高度的优化,使得编码更加轻松,代码容易理解。
- guava
-
添加分页插件pagehelper
- pagehelper
- fastjson
-
hutool工具包
- hutool-all
-
<build>
方式<build> <resources> <!-- 编译之后包含xml --> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <!-- 编译之后包含xml和properties --> <resource> <directory>src/main/resources</directory> <includes> <include>**/*</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
2. src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ForestBlog</display-name>
<!--post乱码过滤器-->
<!-- 配置springMVC编码过滤器 -->
<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:spring/spring-*.xml,
</param-value>
</context-param>
<!--配置监听器,来加载spring容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- logback日志打印 -->
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>classpath:logback.xml</param-value>
</context-param>
<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>
<!--springmvc前端控制器 -->
<servlet>
<servlet-name>ForestBlog</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ForestBlog</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--随时获得request-->
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<!-- 4、使用Rest风格的URI,将页面普通的post请求转为指定的delete或者put请求 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--去掉jsp页面的空白-->
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>
web.xml文件的作用
-
配置欢迎页面
-
配置springMVC编码过滤器
-
加载spring容器
-
配置监听器,来加载spring容器
-
配置logback日志打印
-
springmvc前端控制器
-
配置监听器,随时获得request
-
使用Rest风格的URI,将页面普通的post请求转为指定的delete或者put请求
-
配置WebStatFilter用于采集web-jdbc关联监控的数据。
-
去掉jsp页面的空白
二、分析main文件夹下文件
1. 分析resources文件夹
1.1 文件夹结构
│ db.properties
│ logback.xml
│
├─mapper
│ ArticleCategoryRefMapper.xml
│ ArticleMapper.xml
│ ArticleTagRefMapper.xml
│ CategoryMapper.xml
│ CommentMapper.xml
│ LinkMapper.xml
│ MenuMapper.xml
│ NoticeMapper.xml
│ OptionsMapper.xml
│ PageMapper.xml
│ TagMapper.xml
│ UserMapper.xml
│
├─mybatis
│ mybatis-config.xml
│
└─spring
spring-mvc.xml
spring-mybatis.xml
mapper 文件夹暂不分析,等分析具体映射时再一起分析
1.2 db.properties
-
此文件为数据库连接配置文件
#MySQL mysql.driver=com.mysql.cj.jdbc.Driver mysql.url=jdbc:mysql://localhost:3306/forest_blog?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC mysql.username=root mysql.password=123
1.3 logback.xml
-
此文件为logback日志配置文件
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 尽量别用绝对路径,如果带参数不同容器路径解释可能不同,以下配置参数在pom.xml里 --> <property name="log.root.level" value="INFO"/> <!-- 日志级别 --> <property name="log.other.level" value="ERROR"/> <!-- 其他日志级别 --> <property name="log.base" value="logs"/> <!-- 日志路径,这里是相对路径,默认会输出到tomcat/bin目录 下 --> <property name="log.moduleName" value="ForestBlog"/> <!-- 模块名称, 影响日志配置名,日志文件名 --> <property name="log.max.size" value="20MB"/> <!-- 日志文件大小 --> <!--控制台输出 --> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread]%logger{56}.%method:%L -%msg%n</Pattern> </encoder> </appender> <!-- 日志文件输出 --> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>${log.base}/${log.moduleName}.log </File><!-- 设置日志不超过${log.max.size}时的保存路径,注意如果 是web项目会保存到Tomcat的bin目录 下 --> <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${log.base}/archive/${log.moduleName}_all_%d{yyyy-MM-dd}.%i.log.zip </FileNamePattern> <!-- 当天的日志大小 超过${log.max.size}时,压缩日志并保存 --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>${log.max.size}</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 日志输出的文件的格式 --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread]%logger{56}.%method:%L -%msg%n</pattern> </layout> </appender> </configuration>
1.4 mybatis/mybatis-config.xml
-
此文件为mybatis配置文件
<?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> <!-- 全局配置 --> <settings> <!--允许 JDBC 支持自动生成主键--> <setting name="useGeneratedKeys" value="false"/> <!--是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典Java 属性名 aColumn 的类似映射。 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 打印查询语句 --> <!-- <setting name="logImpl" value="STDOUT_LOGGING" />--> </settings> <!-- 注册分页插件PageHelper --> <plugins> <plugin interceptor="com.github.pagehelper.PageHelper"> <!--<property name="dialect" value="mysql"/>--> <property name="offsetAsPageNum" value="false"/> <property name="rowBoundsWithCount" value="false"/> <property name="pageSizeZero" value="true"/> <property name="reasonable" value="true"/> <property name="supportMethodsArguments" value="false"/> <property name="returnPageInfo" value="none"/> </plugin> </plugins> </configuration>
-
主要任务
- 允许 JDBC 支持自动生成主键
- 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典Java 属性名 aColumn 的类似映射。
- 注册分页插件PageHelper
1.5 spring文件夹
1.5.1 spring-mvc.xml
-
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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.liuyanzhao.ssm.blog"/> <!-- 一个配置节解决映射器和适配器的配置注解配置 --> <mvc:annotation-driven></mvc:annotation-driven> <!-- 配置视图解析器 进行jsp解析,默认使用jstl标签,classpath下得有jstl的包 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置前缀和后缀,也可以不指定--> <property name="prefix" value="/WEB-INF/view/"/> <property name="suffix" value=".jsp"/> </bean> <!--<!–文件上传–>--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--设置上传最大尺寸为50MB--> <property name="maxUploadSizePerFile" value="52428800"/> <property name="defaultEncoding" value="UTF-8"/> <property name="resolveLazily" value="true"/> </bean> <!-- 静态资源映射 --> <mvc:resources mapping="/css/**" location="/resource/assets/css/"></mvc:resources> <mvc:resources mapping="/js/**" location="/resource/assets/js/"></mvc:resources> <mvc:resources mapping="/img/**" location="/resource/assets/img/"></mvc:resources> <mvc:resources mapping="/plugin/**" location="/resource/assets/plugin/"></mvc:resources> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.HomeResourceInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.LoginInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.LoginInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/page"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/page/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/tag"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/tag/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/category"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/category/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/user"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/user/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/menu"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/menu/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/options"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/options/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/link"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/admin/link/**"/> <bean class="com.liuyanzhao.ssm.blog.util.interceptor.AdminInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>
-
主要任务
- 配置包扫描器对动态java文件进行扫描实例化
- 配置视图解析器进行jsp解析,默认使用jstl标签,classpath下得有jstl的包
- 配置文件上传限制
- 对静态资源进行映射
- 注册拦截器
1.5.2 spring-mybatis.xml
-
spring与mybatis的配置文件
<?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" xmlns:tx="http://www.springframework.org/schema/tx" 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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--加载db.properties--> <context:property-placeholder location="classpath:db.properties"/> <!--配置druid连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 基本属性 url、user、password --> <property name="driverClassName" value="${mysql.driver}" /> <property name="url" value="${mysql.url}" /> <property name="username" value="${mysql.username}" /> <property name="password" value="${mysql.password}" /> <!-- 配置初始化大小、最小、最大 --> <property name="initialSize" value="1" /> <property name="minIdle" value="1" /> <property name="maxActive" value="20" /> <!-- 配置获取连接等待超时的时间,单位是毫秒 --> <property name="maxWait" value="60000" /> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000" /> <property name="validationQuery" value="SELECT 'x'" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 --> <property name="filters" value="stat" /> </bean> <!-- mybatis核心配置 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--数据库连接池--> <property name="dataSource" ref="dataSource"/> <!--加载mybatis全局配置文件--> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> <!--mapper.xml所在位置--> <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml" /> <!--指定需要使用别名的PO类所在的包--> <property name="typeAliasesPackage" value="com.liuyanzhao.ssm.blog.entity" /> </bean> <!--mapper扫描器--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--如果需要扫描多个包,中间使用半角逗号隔开--> <property name="basePackage" value="com.liuyanzhao.ssm.blog.mapper"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <!-- 对mybatis操作数据事务控制,spring使用jdbc的事务控制类 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 数据源dataSource在spring-mybatis.xml中配置了 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"/> <tx:method name="get*" propagation="SUPPORTS" read-only="true"/> <tx:method name="select*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.liuyanzhao.ssm.blog.service.impl.*.*(..))"/> </aop:config> </beans>
-
主要任务
- 加载db.properties数据库信息配置文件
- 配置druid连接池信息
- 基本属性 url、user、password
- 配置初始化大小、最小、最大
- 配置获取连接等待超时的时间
- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
- 配置一个连接在池中最小生存的时间,单位是毫秒
- 打开PSCache,并且指定每个连接上PSCache的大小
- 配置监控统计拦截的filters,去掉后监控界面sql无法统计
- mybatis核心配置
- 数据库连接池
- 加载mybatis全局配置文件
- mapper.xml所在位置
- 指定需要使用别名的PO类所在的包
- mapper扫描器
- 如果需要扫描多个包,中间使用半角逗号隔开
- 对mybatis操作数据事务控制,spring使用jdbc的事务控制类
- 数据源dataSource在spring-mybatis.xml中配置了
- 定义通知advice
- 配置切面
2. 分析java文件夹
2.1 文件夹结构
└─com
└─liuyanzhao
└─ssm
└─blog
├─controller
│ ├─admin
│ │ AdminController.java
│ │ BackArticleController.java
│ │ BackCategoryController.java
│ │ BackCommentController.java
│ │ BackLinkController.java
│ │ BackMenuController.java
│ │ BackNoticeController.java
│ │ BackOptionsController.java
│ │ BackPageController.java
│ │ BackTagController.java
│ │ BackUserController.java
│ │ UploadFileController.java
│ │
│ └─home
│ ArticleController.java
│ CategoryController.java
│ CommentController.java
│ IndexController.java
│ LinkController.java
│ NoticeController.java
│ PageController.java
│ TagController.java
│
├─dto
│ ArticleParam.java
│ JsonResult.java
│ ResultVO.java
│ UploadFileVO.java
│
├─entity
│ Article.java
│ ArticleCategoryRef.java
│ ArticleTagRef.java
│ Category.java
│ Comment.java
│ Link.java
│ Menu.java
│ Notice.java
│ Options.java
│ Page.java
│ Tag.java
│ User.java
│
├─enums
│ ArticleCommentStatus.java
│ ArticleStatus.java
│ CategoryStatus.java
│ LinkStatus.java
│ MenuLevel.java
│ NoticeStatus.java
│ PageStatus.java
│ Role.java
│ UserRole.java
│
├─mapper
│ ArticleCategoryRefMapper.java
│ ArticleMapper.java
│ ArticleTagRefMapper.java
│ CategoryMapper.java
│ CommentMapper.java
│ LinkMapper.java
│ MenuMapper.java
│ NoticeMapper.java
│ OptionsMapper.java
│ PageMapper.java
│ TagMapper.java
│ UserMapper.java
│
├─service
│ │ ArticleService.java
│ │ CategoryService.java
│ │ CommentService.java
│ │ LinkService.java
│ │ MenuService.java
│ │ NoticeService.java
│ │ OptionsService.java
│ │ PageService.java
│ │ TagService.java
│ │ UserService.java
│ │
│ └─impl
│ ArticleServiceImpl.java
│ CategoryServiceImpl.java
│ CommentServiceImpl.java
│ LinkServiceImpl.java
│ MenuServiceImpl.java
│ NoticeServiceImpl.java
│ OptionsServiceImpl.java
│ PageServiceImpl.java
│ TagServiceImpl.java
│ UserServiceImpl.java
│
└─util
│ MyUtils.java
│
└─interceptor
AdminInterceptor.java
HomeResourceInterceptor.java
LoginInterceptor.java
由于包名为com.liuyanzhao.ssm.blog,其余文件都在该目录下进行分类,因此以下分析默认在此目录下进行。
2.2 entity实体类
2.2.0 实例关系分析
-
实体基础需求
- 文章(文章ID,用户ID,文章标题,文章访问量,文章评论数,文章点赞数,文章创建时间,文章更新时间,文章能否评论,文章状态,文章排序值,文章内容,文章摘要,文章缩略图)
- 分类(分类ID,父亲ID,分类名称,分类描述,分类排序值,分类图标)
- 标签(标签ID,标签名称,标签描述)
- 用户(用户ID,用户名,密码,用户昵称,用户邮箱,用户主页url,用户头像,用户上次登录IP,用户注册时间,用户上次登录时间,用户状态,用户角色)
- 评论(评论ID,上级评论人ID,上级评论人名称,评论文章ID,评论人昵称,评论人email,评论人主页url,评论人头像,评论内容,评论浏览器信息,评论IP,评论时间,评论角色,评论用户ID)
------------------------下方为管理员管理内容-------------------------------
- 链接(链接ID,链接url,链接名称,链接头像,链接描述,链接所属人昵称,链接所属人联系方式,链接创建时间,链接更新时间,链接排序值,链接状态)
- 菜单(菜单ID,菜单名称,菜单url,菜单等级,菜单图标,菜单排序值)
- 公告(公告ID,公告标题,公告内容,公告创建时间,公告更新时间,公告状态,公告排序值)
- 基本信息(基本信息ID,站点标题,站点描述,媒体描述,媒体关键字,相关站点头像,相关站点标题,相关站点内容,相关站点微信,相关站点QQ,相关站点GitHub,相关站点微博,基本信息统计,基本信息状态)
- 页面(页面ID,页面别称key,页面标题,页面内容,页面创建时间,页面更新时间,页面访问量,页面评论数,页面状态)
-
关系模式
- 文章:分类 = m:n
- 文章:标签 = m:n
- 文章:用户 = n:1
- 文章:评论 = 1:n
- 父分类:子分类 = 1:1
- 用户:评论 = 1:n
- 父评论:子评论 = 1:1
-
加入关系模式后的实体类设计
- 文章(文章ID,文章标题,文章访问量,文章评论数,文章点赞数,文章创建时间,文章更新时间,文章能否评论,文章状态,文章排序值,文章内容,文章摘要,文章缩略图,用户ID)
- PK:文章ID,用户ID
- FK:用户ID
- 分类(分类ID,父亲分类ID,分类名称,分类描述,分类排序值,分类图标)
- PK:分类ID,父亲分类ID
- FK:父亲分类ID
- 标签(标签ID,标签名称,标签描述)
- PK:标签ID
- FK:
- 用户(用户ID,用户名,密码,用户昵称,用户邮箱,用户主页url,用户头像,用户上次登录IP,用户注册时间,用户上次登录时间,用户状态,用户角色)
- PK:用户ID
- FK:
- 评论(评论ID,评论人昵称,评论人email,评论人主页url,评论人头像,评论内容,评论浏览器信息,评论IP,评论时间,评论角色,上级评论人ID,上级评论人名称,评论文章ID,评论用户ID)
- PK:评论ID,评论文章ID,上级评论人ID,评论用户ID
- FK:评论文章ID,上级评论人ID,评论用户ID
- 文章与分类关系(文章ID,分类ID)
- PK:文章ID,分类ID
- FK:文章ID,分类ID
- 文章与标签关系(文章ID,标签ID)
- PK:文章ID,标签ID
- FK:文章ID,标签ID
------------------------下方为管理员管理内容-------------------------------
- 链接(链接ID,链接url,链接名称,链接头像,链接描述,链接所属人昵称,链接所属人联系方式,链接创建时间,链接更新时间,链接排序值,链接状态)
- PK:链接ID
- FK:
- 菜单(菜单ID,菜单名称,菜单url,菜单等级,菜单图标,菜单排序值)
- PK:菜单ID
- FK:
- 公告(公告ID,公告标题,公告内容,公告创建时间,公告更新时间,公告状态,公告排序值)
- PK:公告ID
- FK:
- 基本信息(基本信息ID,站点标题,站点描述,媒体描述,媒体关键字,相关站点头像,相关站点标题,相关站点内容,相关站点微信,相关站点QQ,相关站点GitHub,相关站点微博,基本信息统计,基本信息状态)
- PK:基本信息ID
- FK:
- 页面(页面ID,页面别称key,页面标题,页面内容,页面创建时间,页面更新时间,页面访问量,页面评论数,页面状态)
- PK:页面ID
- FK:
- 文章(文章ID,文章标题,文章访问量,文章评论数,文章点赞数,文章创建时间,文章更新时间,文章能否评论,文章状态,文章排序值,文章内容,文章摘要,文章缩略图,用户ID)
-
为增加查询效率,增加冗余,最终实体类设计
- 文章(文章ID,文章标题,文章访问量,文章评论数,文章点赞数,文章创建时间,文章更新时间,文章能否评论,文章状态,文章排序值,文章内容,文章摘要,文章缩略图,用户ID,用户,标签列表,分类列表)
- PK:文章ID,用户ID
- FK:用户ID
- 冗余属性:用户,标签列表,分类列表
- 分类(分类ID,父亲分类ID,分类名称,分类描述,分类排序值,分类图标,该分类下的文章数量)
- PK:分类ID,父亲分类ID
- FK:父亲分类ID
- 冗余属性:该分类下的文章总数
- 标签(标签ID,标签名称,标签描述,该标签下的文章数量)
- PK:标签ID
- FK:
- 冗余属性:该标签下的文章总数
- 用户(用户ID,用户名,密码,用户昵称,用户邮箱,用户主页url,用户头像,用户上次登录IP,用户注册时间,用户上次登录时间,用户状态,用户角色,该用户写的文章数量)
- PK:用户ID
- FK:
- 冗余属性:该用户写的文章数量
- 评论(评论ID,评论人昵称,评论人email,评论人主页url,评论人头像,评论内容,评论浏览器信息,评论IP,评论时间,评论角色,上级评论人ID,上级评论人名称,评论文章ID,评论用户ID,文章)
- PK:评论ID,评论文章ID,上级评论人ID,评论用户ID
- FK:评论文章ID,上级评论人ID,评论用户ID
- 冗余属性:文章
- 文章与分类关系(文章ID,分类ID)
- PK:文章ID,分类ID
- FK:文章ID,分类ID
- 文章与标签关系(文章ID,标签ID)
- PK:文章ID,标签ID
- FK:文章ID,标签ID
------------------------下方为管理员管理内容-------------------------------
- 链接(链接ID,链接url,链接名称,链接头像,链接描述,链接所属人昵称,链接所属人联系方式,链接创建时间,链接更新时间,链接排序值,链接状态)
- PK:链接ID
- FK:
- 菜单(菜单ID,菜单名称,菜单url,菜单等级,菜单图标,菜单排序值)
- PK:菜单ID
- FK:
- 公告(公告ID,公告标题,公告内容,公告创建时间,公告更新时间,公告状态,公告排序值)
- PK:公告ID
- FK:
- 基本信息(基本信息ID,站点标题,站点描述,媒体描述,媒体关键字,相关站点头像,相关站点标题,相关站点内容,相关站点微信,相关站点QQ,相关站点GitHub,相关站点微博,基本信息统计,基本信息状态)
- PK:基本信息ID
- FK:
- 页面(页面ID,页面别称key,页面标题,页面内容,页面创建时间,页面更新时间,页面访问量,页面评论数,页面状态)
- PK:页面ID
- FK:
- 文章(文章ID,文章标题,文章访问量,文章评论数,文章点赞数,文章创建时间,文章更新时间,文章能否评论,文章状态,文章排序值,文章内容,文章摘要,文章缩略图,用户ID,用户,标签列表,分类列表)
├─entity
│ Article.java
│ ArticleCategoryRef.java
│ ArticleTagRef.java
│ Category.java
│ Comment.java
│ Link.java
│ Menu.java
│ Notice.java
│ Options.java
│ Page.java
│ Tag.java
│ User.java
-
该目录下的实体类均采用@Data注解,简化代码。
-
@Data 的用途是:注在类上,提供类的get、set、equals、hashCode、toString等方法。
-
使用该注解需要引入lombok依赖,idea中需要引入lombok相关插件。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.22</version> </dependency>
2.2.1 Article
-
com.liuyanzhao.ssm.blog.entity.Article
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; import java.util.List; /** * @author liuyanzhao */ @Data public class Article implements Serializable{ private static final long serialVersionUID = 5207865247400761539L; // 文章ID private Integer articleId; // 文章用户ID private Integer articleUserId; // 文章标题 private String articleTitle; // 文章访问量 private Integer articleViewCount; // 文章评论数 private Integer articleCommentCount; // 文章点赞数 private Integer articleLikeCount; // 文章创建时间 private Date articleCreateTime; // 文章更新时间 private Date articleUpdateTime; // 文章是否允许评论 private Integer articleIsComment; // 文章状态 private Integer articleStatus; // 文章排序值 private Integer articleOrder; // 文章内容 private String articleContent; // 文章摘要 private String articleSummary; // 文章缩略图 private String articleThumbnail; private User user; private List<Tag> tagList; private List<Category> categoryList; }
-
文章实体类
- 增加了三个非数据库属性
- User:用户
- tagList:标签列表
- categoryList:分类列表
- 增加了三个非数据库属性
-
数据库设计
-
2.2.2 ArticleCategoryRef
-
com.liuyanzhao.ssm.blog.entity.ArticleCategoryRef
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * 文章分类关联表 * * @author liuyanzhao */ @Data public class ArticleCategoryRef implements Serializable{ private static final long serialVersionUID = -6809206515467725995L; // 文章ID private Integer articleId; // 分类ID private Integer categoryId; public ArticleCategoryRef() { } public ArticleCategoryRef(Integer articleId, Integer categoryId) { this.articleId = articleId; this.categoryId = categoryId; } }
-
文章分类关联表实体类
-
数据库设计
-
2.2.3 ArticleTagRef
-
com.liuyanzhao.ssm.blog.entity.ArticleTagRef
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * 文章和标签关联 * * @author 言曌 * @date 2018/11/17 下午5:20 */ @Data public class ArticleTagRef implements Serializable { private static final long serialVersionUID = -5816783232020910492L; // 文章ID private Integer articleId; // 标签ID private Integer tagId; public ArticleTagRef() { } public ArticleTagRef(Integer articleId, Integer tagId) { this.articleId = articleId; this.tagId = tagId; } }
-
文章和标签关联实体类
-
数据库设计
-
2.2.4 Category
-
com.liuyanzhao.ssm.blog.entity.Category
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * @author liuyanzhao */ @Data public class Category implements Serializable { private static final long serialVersionUID = 6687286913317513141L; // 分类ID private Integer categoryId; // 分类父ID private Integer categoryPid; // 分类名称 private String categoryName; // 分类描述 private String categoryDescription; // 分类排序值 private Integer categoryOrder; // 分类图标 private String categoryIcon; /** * 文章数量(非数据库字段) */ private Integer articleCount; public Category(Integer categoryId, Integer categoryPid, String categoryName, String categoryDescription, Integer categoryOrder, String categoryIcon,Integer articleCount) { this.categoryId = categoryId; this.categoryPid = categoryPid; this.categoryName = categoryName; this.categoryDescription = categoryDescription; this.categoryOrder = categoryOrder; this.categoryIcon = categoryIcon; this.articleCount = articleCount; } public Category(Integer categoryId, String categoryName) { this.categoryId = categoryId; this.categoryName = categoryName; } public Category(Integer categoryId) { this.categoryId = categoryId; } public Category() {} /** * 未分类 * * @return 分类 */ public static Category Default() { return new Category(100000000, "未分类"); } }
-
分类实体类
- 增加了一个非数据库属性
- articleCount:该分类下的文章数量
- 设计了构造方法,包括:
- 仅有分类ID
- 有分类ID、分类名称
- 全参
- 设置了一个静态方法:Default(),用于返回一个固定内容的未分类对象
- 增加了一个非数据库属性
-
数据库设计
-
2.2.5 Comment
-
com.liuyanzhao.ssm.blog.entity.Comment
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * 文章评论 * * @author liuyanzhao */ @Data public class Comment implements Serializable { private static final long serialVersionUID = -1038897351672911219L; // 评论ID private Integer commentId; // 上级评论ID private Integer commentPid; // 上级评论名称 private String commentPname; // 文章ID private Integer commentArticleId; // 评论人名称 private String commentAuthorName; // 评论人邮箱 private String commentAuthorEmail; // 评论人个人主页 private String commentAuthorUrl; // 评论人头像 private String commentAuthorAvatar; // 内容 private String commentContent; // 浏览器信息 private String commentAgent; // IP private String commentIp; // 评论时间 private Date commentCreateTime; /** * 角色(管理员1,访客0) */ private Integer commentRole; /** * 评论用户ID */ private Integer commentUserId; /** * 非数据库字段 */ private Article article; }
-
评论实体类
- 增加了一个非数据库属性:article:文章
-
数据库设计
-
2.2.6 Link
-
com.liuyanzhao.ssm.blog.entity.Link
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @author liuyanzhao */ @Data public class Link implements Serializable{ private static final long serialVersionUID = -259829372268790508L; // 链接ID private Integer linkId; // URL private String linkUrl; // 姓名 private String linkName; // 头像 private String linkImage; // 描述 private String linkDescription; // 所属人名称 private String linkOwnerNickname; // 联系方式 private String linkOwnerContact; // 更新时间 private Date linkUpdateTime; // 创建时间 private Date linkCreateTime; // 排序号 private Integer linkOrder; // 状态 private Integer linkStatus; }
-
连接实体类
-
数据库设计
-
2.2.7 Menu
-
com.liuyanzhao.ssm.blog.entity.Menu
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * @author liuyanzhao */ @Data public class Menu implements Serializable { private static final long serialVersionUID = 489914127235951698L; // 菜单ID private Integer menuId; // 名称 private String menuName; // URL private String menuUrl; // 等级 private Integer menuLevel; // 图标 private String menuIcon; // 排序值 private Integer menuOrder; }
-
菜单实体类
-
数据库设计
-
2.2.8 Notice
-
com.liuyanzhao.ssm.blog.entity.Notice
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @author liuyanzhao */ @Data public class Notice implements Serializable{ private static final long serialVersionUID = -4901560494243593100L; // 公告ID private Integer noticeId; // 公告标题 private String noticeTitle; // 内容 private String noticeContent; // 创建时间 private Date noticeCreateTime; // 更新时间 private Date noticeUpdateTime; // 状态 private Integer noticeStatus; // 排序值 private Integer noticeOrder; }
-
公告实体类
-
数据库设计
-
2.2.9 Options
-
com.liuyanzhao.ssm.blog.entity.Options
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * @author liuyanzhao */ @Data public class Options implements Serializable{ private static final long serialVersionUID = -776792869602511933L; // private Integer optionId; // private String optionSiteTitle; // private String optionSiteDescrption; // private String optionMetaDescrption; // private String optionMetaKeyword; // private String optionAboutsiteAvatar; // private String optionAboutsiteTitle; // private String optionAboutsiteContent; // private String optionAboutsiteWechat; // private String optionAboutsiteQq; // private String optionAboutsiteGithub; // private String optionAboutsiteWeibo; // private String optionTongji; // private Integer optionStatus; }
-
系统设置实体类
-
数据库设计
-
2.2.10 Page
-
com.liuyanzhao.ssm.blog.entity.Page
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @author liuyanzhao */ @Data public class Page implements Serializable{ private static final long serialVersionUID = 3927496662110298634L; // 自定义页面ID private Integer pageId; // key private String pageKey; // 标题 private String pageTitle; // 内容 private String pageContent; // 创建时间 private Date pageCreateTime; // 更新时间 private Date pageUpdateTime; // 访问量 private Integer pageViewCount; // 评论数 private Integer pageCommentCount; // 状态 private Integer pageStatus; }
-
页面实体类
-
数据库设计
-
2.2.11 Tag
-
com.liuyanzhao.ssm.blog.entity.Tag
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * @author liuyanzhao */ @Data public class Tag implements Serializable{ private static final long serialVersionUID = 605449151900057035L; // 标签ID private Integer tagId; // 标签名称 private String tagName; // 描述 private String tagDescription; /** * 文章数量(不是数据库字段) */ private Integer articleCount; public Tag() { } public Tag(Integer tagId) { this.tagId = tagId; } public Tag(Integer tagId, String tagName, String tagDescription, Integer articleCount) { this.tagId = tagId; this.tagName = tagName; this.tagDescription = tagDescription; this.articleCount = articleCount; } }
-
标签实体类
- 增加了一个非数据库属性:articleCount:文章数量总计
- 增加了三个构造方法
- 无参
- 单一标签ID
- 全参
-
数据库设计
-
2.2.12 User
-
com.liuyanzhao.ssm.blog.entity.User
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @author liuyanzhao */ @Data public class User implements Serializable{ private static final long serialVersionUID = -4415517704211731385L; // 用户ID private Integer userId; // 用户名 private String userName; // 密码 private String userPass; // 昵称 private String userNickname; // 邮箱 private String userEmail; // 个人主页 private String userUrl; // 头像 private String userAvatar; // 上次登录IP private String userLastLoginIp; // 注册时间 private Date userRegisterTime; // 上次登录时间 private Date userLastLoginTime; // 状态 private Integer userStatus; /** * 用户角色:admin/user */ private String userRole; /** * 文章数量(不是数据库字段) */ private Integer articleCount; }
-
用户实体类
- 增加一个非数据库属性:articleCount:发布文章总数
-
数据库设计
-
2.3 enums枚举类
├─enums
│ ArticleCommentStatus.java
│ ArticleStatus.java
│ CategoryStatus.java
│ LinkStatus.java
│ MenuLevel.java
│ NoticeStatus.java
│ PageStatus.java
│ Role.java
│ UserRole.java
2.3.1 ArticleCommentStatus
-
com.liuyanzhao.ssm.blog.enums.ArticleCommentStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum ArticleCommentStatus { ALLOW(1, "允许"), NOT_ALLOW(0, "不允许"); private Integer value; private String message; ArticleCommentStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 文章是否允许评论
- 1:允许
- 0:不允许
- 文章是否允许评论
2.3.2 ArticleStatus
-
com.liuyanzhao.ssm.blog.enums.ArticleStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum ArticleStatus { PUBLISH(1, "已发布"), DRAFT(0, "草稿"); private Integer value; private String message; ArticleStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 文章状态
- 1:已发布
- 0:草稿
- 文章状态
2.3.3 CategoryStatus
-
com.liuyanzhao.ssm.blog.enums.CategoryStatus
package com.liuyanzhao.ssm.blog.enums; import lombok.Data; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum CategoryStatus { NORMAL(1, "正常"), HIDDEN(0, "隐藏"); private Integer value; private String message; CategoryStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 分类状态
- 1:正常
- 0:隐藏
- 分类状态
2.3.4 LinkStatus
-
com.liuyanzhao.ssm.blog.enums.LinkStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum LinkStatus { NORMAL(1, "显示"), HIDDEN(0, "隐藏"); private Integer value; private String message; LinkStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 链接状态
- 1:显示
- 0:隐藏
- 链接状态
2.3.5 MenuLevel
-
com.liuyanzhao.ssm.blog.enums.MenuLevel
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum MenuLevel { TOP_MENU(1, "顶部菜单"), MAIN_MENU(2, "主体菜单"); private Integer value; private String message; MenuLevel(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 菜单等级
- 1:顶部菜单
- 2:主体菜单
- 菜单等级
2.3.6 NoticeStatus
-
com.liuyanzhao.ssm.blog.enums.NoticeStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum NoticeStatus { NORMAL(1, "显示"), HIDDEN(0, "隐藏"); private Integer value; private String message; NoticeStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 通知状态
- 1:显示
- 0:隐藏
- 通知状态
2.3.7 PageStatus
-
com.liuyanzhao.ssm.blog.enums.PageStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum PageStatus { NORMAL(1, "显示"), HIDDEN(0, "隐藏"); private Integer value; private String message; PageStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 页面状态
- 1:显示
- 0:隐藏
- 页面状态
2.3.8 Role
-
com.liuyanzhao.ssm.blog.enums.Role
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum Role { OWNER(1, "博主"), VISITOR(0, "其他用户"); private Integer value; private String message; Role(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 浏览角色
- 1:博主
- 0:其他用户
- 浏览角色
2.3.9 UserRole
-
com.liuyanzhao.ssm.blog.enums.UserRole
package com.liuyanzhao.ssm.blog.enums; /** * 角色枚举 * * @author 言曌 * @date 2021/2/25 2:31 下午 */ public enum UserRole { ADMIN("admin", "管理员"), USER("user", "用户"); private String value; private String message; UserRole(String value, String message) { this.value = value; this.message = message; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 用户角色
- admin:管理员
- user:用户
- 用户角色
2.4 dto数据传输对象
├─dto
│ ArticleParam.java
│ JsonResult.java
│ ResultVO.java
│ UploadFileVO.java
2.4.1 ArticleParam
-
com.liuyanzhao.ssm.blog.dto.ArticleParam
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; import java.util.List; /** * @author 言曌 * @date 2018/11/25 下午3:56 */ @Data public class ArticleParam { private Integer articleId; private String articleTitle; private String articleContent; private Integer articleParentCategoryId; private Integer articleChildCategoryId; private Integer articleOrder; private Integer articleStatus; private String articleThumbnail; private List<Integer> articleTagIds; }
- 文章参数
2.4.2 JsonResult
-
com.liuyanzhao.ssm.blog.dto.JsonResult
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; /** * @author 言曌 * @date 2017/11/30 下午7:04 */ @Data public class JsonResult<T> { /** * 错误码 */ private Integer code; /** * 提示信息 */ private String msg; /** * 返回的具体内容 */ private T data; public JsonResult(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public JsonResult() { } public JsonResult fail() { return new JsonResult(1, "操作失败", null); } public JsonResult fail(String msg) { return new JsonResult(1, msg, null); } public JsonResult ok() { return new JsonResult(0, "操作成功", null); } public JsonResult ok(T data) { return new JsonResult(0, "操作成功", data); } }
- json传输结果
2.4.3 ResultVO
-
com.liuyanzhao.ssm.blog.dto.ResultVO
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; /** * @author 言曌 * @date 2017/11/30 下午7:04 */ @Data public class ResultVO<T> { /** * 错误码 */ private Integer code; /** * 提示信息 */ private String msg; /** * 返回的具体内容 */ private T data; public ResultVO(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public ResultVO() { } }
- 结果显示层对象
2.4.4 UploadFileVO
-
com.liuyanzhao.ssm.blog.dto.UploadFileVO
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; /** * @author 言曌 * @date 2017/11/30 下午7:41 */ @Data public class UploadFileVO { private String src; private String title; }
- 上传文件显示层对象
2.5 util工具类
└─util
│ MyUtils.java
│
└─interceptor
AdminInterceptor.java
HomeResourceInterceptor.java
LoginInterceptor.java
2.5.1 MyUtils 我的工具类
-
com.liuyanzhao.ssm.blog.util.MyUtils
package com.liuyanzhao.ssm.blog.util; import javax.servlet.http.HttpServletRequest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 常用的方法 * Created by 言曌 on 2017/8/24. */ public class MyUtils { /** * 获得IP地址 * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { String ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; } /** * 获得Md5加密 * * @param str 原字符串 * @return 加密后的字符串 */ public static String strToMd5(String str) { String md5Str = null; if (str != null && str.length() != 0) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) { i += 256; } if (i < 16) { buf.append("0"); } buf.append(Integer.toHexString(i)); } //32位 md5Str = buf.toString(); //16位 //md5Str = buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } return md5Str; } /** * 根据email获取gravatar头像 * * @param email Email * @return 头像URL */ public static String getGravatar(String email) { String emailMd5 = strToMd5(email); //设置图片大小32px String avatar = "http://cn.gravatar.com/avatar/" + emailMd5 + "?s=128&d=identicon&r=PG"; return avatar; } }
-
getIpAddr(HttpServletRequest request)
-
获得IP地址
- @param request HttpServletRequest请求
- @return IP地址
-
源代码
public static String getIpAddr(HttpServletRequest request) { String ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; }
-
自上而下分别从
request.getHeader("x-forwarded-for")
;、request.getHeader("Proxy-Client-IP");
、request.getHeader("WL-Proxy-Client-IP");
和request.getRemoteAddr();
获取IP地址,若未从上方获取则进入下层获取。 -
获取完毕后,若是多个代理的情况,则取第一个IP为客户端真实IP
-
-
String strToMd5(String str)
-
获得Md5加密
- @param str 原字符串
- @return 加密后的字符串
-
源代码
public static String strToMd5(String str) { String md5Str = null; if (str != null && str.length() != 0) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) { i += 256; } if (i < 16) { buf.append("0"); } buf.append(Integer.toHexString(i)); } //32位 md5Str = buf.toString(); //16位 //md5Str = buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }
-
-
String getGravatar(String email)
-
根据email获取gravatar头像
- @param email Email
- @return 头像URL
-
源代码
public static String getGravatar(String email) { String emailMd5 = strToMd5(email); //设置图片大小32px String avatar = "http://cn.gravatar.com/avatar/" + emailMd5 + "?s=128&d=identicon&r=PG"; return avatar; }
-
-
2.2.11 Tag
-
com.liuyanzhao.ssm.blog.entity.Tag
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; /** * @author liuyanzhao */ @Data public class Tag implements Serializable{ private static final long serialVersionUID = 605449151900057035L; // 标签ID private Integer tagId; // 标签名称 private String tagName; // 描述 private String tagDescription; /** * 文章数量(不是数据库字段) */ private Integer articleCount; public Tag() { } public Tag(Integer tagId) { this.tagId = tagId; } public Tag(Integer tagId, String tagName, String tagDescription, Integer articleCount) { this.tagId = tagId; this.tagName = tagName; this.tagDescription = tagDescription; this.articleCount = articleCount; } }
-
标签实体类
- 增加了一个非数据库属性:articleCount:文章数量总计
- 增加了三个构造方法
- 无参
- 单一标签ID
- 全参
-
数据库设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pbeg5QkS-1675858523534)(C:\Users\ShiningSong\AppData\Roaming\Typora\typora-user-images\image-20230205151553132.png)]
-
2.2.12 User
-
com.liuyanzhao.ssm.blog.entity.User
package com.liuyanzhao.ssm.blog.entity; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @author liuyanzhao */ @Data public class User implements Serializable{ private static final long serialVersionUID = -4415517704211731385L; // 用户ID private Integer userId; // 用户名 private String userName; // 密码 private String userPass; // 昵称 private String userNickname; // 邮箱 private String userEmail; // 个人主页 private String userUrl; // 头像 private String userAvatar; // 上次登录IP private String userLastLoginIp; // 注册时间 private Date userRegisterTime; // 上次登录时间 private Date userLastLoginTime; // 状态 private Integer userStatus; /** * 用户角色:admin/user */ private String userRole; /** * 文章数量(不是数据库字段) */ private Integer articleCount; }
-
用户实体类
- 增加一个非数据库属性:articleCount:发布文章总数
-
数据库设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AljMObZN-1675858523535)(C:\Users\ShiningSong\AppData\Roaming\Typora\typora-user-images\image-20230205151644431.png)]
-
2.3 enums枚举类
├─enums
│ ArticleCommentStatus.java
│ ArticleStatus.java
│ CategoryStatus.java
│ LinkStatus.java
│ MenuLevel.java
│ NoticeStatus.java
│ PageStatus.java
│ Role.java
│ UserRole.java
2.3.1 ArticleCommentStatus
-
com.liuyanzhao.ssm.blog.enums.ArticleCommentStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum ArticleCommentStatus { ALLOW(1, "允许"), NOT_ALLOW(0, "不允许"); private Integer value; private String message; ArticleCommentStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 文章是否允许评论
- 1:允许
- 0:不允许
- 文章是否允许评论
2.3.2 ArticleStatus
-
com.liuyanzhao.ssm.blog.enums.ArticleStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum ArticleStatus { PUBLISH(1, "已发布"), DRAFT(0, "草稿"); private Integer value; private String message; ArticleStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 文章状态
- 1:已发布
- 0:草稿
- 文章状态
2.3.3 CategoryStatus
-
com.liuyanzhao.ssm.blog.enums.CategoryStatus
package com.liuyanzhao.ssm.blog.enums; import lombok.Data; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum CategoryStatus { NORMAL(1, "正常"), HIDDEN(0, "隐藏"); private Integer value; private String message; CategoryStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 分类状态
- 1:正常
- 0:隐藏
- 分类状态
2.3.4 LinkStatus
-
com.liuyanzhao.ssm.blog.enums.LinkStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum LinkStatus { NORMAL(1, "显示"), HIDDEN(0, "隐藏"); private Integer value; private String message; LinkStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 链接状态
- 1:显示
- 0:隐藏
- 链接状态
2.3.5 MenuLevel
-
com.liuyanzhao.ssm.blog.enums.MenuLevel
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum MenuLevel { TOP_MENU(1, "顶部菜单"), MAIN_MENU(2, "主体菜单"); private Integer value; private String message; MenuLevel(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 菜单等级
- 1:顶部菜单
- 2:主体菜单
- 菜单等级
2.3.6 NoticeStatus
-
com.liuyanzhao.ssm.blog.enums.NoticeStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum NoticeStatus { NORMAL(1, "显示"), HIDDEN(0, "隐藏"); private Integer value; private String message; NoticeStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 通知状态
- 1:显示
- 0:隐藏
- 通知状态
2.3.7 PageStatus
-
com.liuyanzhao.ssm.blog.enums.PageStatus
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum PageStatus { NORMAL(1, "显示"), HIDDEN(0, "隐藏"); private Integer value; private String message; PageStatus(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 页面状态
- 1:显示
- 0:隐藏
- 页面状态
2.3.8 Role
-
com.liuyanzhao.ssm.blog.enums.Role
package com.liuyanzhao.ssm.blog.enums; /** * @author 言曌 * @date 2018/11/17 下午4:47 */ public enum Role { OWNER(1, "博主"), VISITOR(0, "其他用户"); private Integer value; private String message; Role(Integer value, String message) { this.value = value; this.message = message; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 浏览角色
- 1:博主
- 0:其他用户
- 浏览角色
2.3.9 UserRole
-
com.liuyanzhao.ssm.blog.enums.UserRole
package com.liuyanzhao.ssm.blog.enums; /** * 角色枚举 * * @author 言曌 * @date 2021/2/25 2:31 下午 */ public enum UserRole { ADMIN("admin", "管理员"), USER("user", "用户"); private String value; private String message; UserRole(String value, String message) { this.value = value; this.message = message; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
- 用户角色
- admin:管理员
- user:用户
- 用户角色
2.4 dto数据传输对象
├─dto
│ ArticleParam.java
│ JsonResult.java
│ ResultVO.java
│ UploadFileVO.java
2.4.1 ArticleParam
-
com.liuyanzhao.ssm.blog.dto.ArticleParam
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; import java.util.List; /** * @author 言曌 * @date 2018/11/25 下午3:56 */ @Data public class ArticleParam { private Integer articleId; private String articleTitle; private String articleContent; private Integer articleParentCategoryId; private Integer articleChildCategoryId; private Integer articleOrder; private Integer articleStatus; private String articleThumbnail; private List<Integer> articleTagIds; }
- 文章参数
2.4.2 JsonResult
-
com.liuyanzhao.ssm.blog.dto.JsonResult
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; /** * @author 言曌 * @date 2017/11/30 下午7:04 */ @Data public class JsonResult<T> { /** * 错误码 */ private Integer code; /** * 提示信息 */ private String msg; /** * 返回的具体内容 */ private T data; public JsonResult(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public JsonResult() { } public JsonResult fail() { return new JsonResult(1, "操作失败", null); } public JsonResult fail(String msg) { return new JsonResult(1, msg, null); } public JsonResult ok() { return new JsonResult(0, "操作成功", null); } public JsonResult ok(T data) { return new JsonResult(0, "操作成功", data); } }
- json传输结果
2.4.3 ResultVO
-
com.liuyanzhao.ssm.blog.dto.ResultVO
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; /** * @author 言曌 * @date 2017/11/30 下午7:04 */ @Data public class ResultVO<T> { /** * 错误码 */ private Integer code; /** * 提示信息 */ private String msg; /** * 返回的具体内容 */ private T data; public ResultVO(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public ResultVO() { } }
- 结果显示层对象
2.4.4 UploadFileVO
-
com.liuyanzhao.ssm.blog.dto.UploadFileVO
package com.liuyanzhao.ssm.blog.dto; import lombok.Data; /** * @author 言曌 * @date 2017/11/30 下午7:41 */ @Data public class UploadFileVO { private String src; private String title; }
- 上传文件显示层对象
2.5 util工具类
└─util
│ MyUtils.java
│
└─interceptor
AdminInterceptor.java
HomeResourceInterceptor.java
LoginInterceptor.java
2.5.1 MyUtils 我的工具类
-
com.liuyanzhao.ssm.blog.util.MyUtils
package com.liuyanzhao.ssm.blog.util; import javax.servlet.http.HttpServletRequest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 常用的方法 * Created by 言曌 on 2017/8/24. */ public class MyUtils { /** * 获得IP地址 * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { String ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; } /** * 获得Md5加密 * * @param str 原字符串 * @return 加密后的字符串 */ public static String strToMd5(String str) { String md5Str = null; if (str != null && str.length() != 0) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) { i += 256; } if (i < 16) { buf.append("0"); } buf.append(Integer.toHexString(i)); } //32位 md5Str = buf.toString(); //16位 //md5Str = buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } return md5Str; } /** * 根据email获取gravatar头像 * * @param email Email * @return 头像URL */ public static String getGravatar(String email) { String emailMd5 = strToMd5(email); //设置图片大小32px String avatar = "http://cn.gravatar.com/avatar/" + emailMd5 + "?s=128&d=identicon&r=PG"; return avatar; } }
-
getIpAddr(HttpServletRequest request)
-
获得IP地址
- @param request HttpServletRequest请求
- @return IP地址
-
源代码
public static String getIpAddr(HttpServletRequest request) { String ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); } //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(",") > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } return ipAddress; }
-
自上而下分别从
request.getHeader("x-forwarded-for")
;、request.getHeader("Proxy-Client-IP");
、request.getHeader("WL-Proxy-Client-IP");
和request.getRemoteAddr();
获取IP地址,若未从上方获取则进入下层获取。 -
获取完毕后,若是多个代理的情况,则取第一个IP为客户端真实IP
-
-
String strToMd5(String str)
-
获得Md5加密
- @param str 原字符串
- @return 加密后的字符串
-
源代码
public static String strToMd5(String str) { String md5Str = null; if (str != null && str.length() != 0) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) { i += 256; } if (i < 16) { buf.append("0"); } buf.append(Integer.toHexString(i)); } //32位 md5Str = buf.toString(); //16位 //md5Str = buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } }
-
-
String getGravatar(String email)
-
根据email获取gravatar头像
- @param email Email
- @return 头像URL
-
源代码
public static String getGravatar(String email) { String emailMd5 = strToMd5(email); //设置图片大小32px String avatar = "http://cn.gravatar.com/avatar/" + emailMd5 + "?s=128&d=identicon&r=PG"; return avatar; }
-
-