1、父工程依赖管理
- 版本声明
<properties>
<!-- 声明属性,对 Spring 的版本进行统一管理 -->
<atguigu.spring.version>4.3.20.RELEASE</atguigu.spring.version>
<!-- 声明属性,对 SpringSecurity 的版本进行统一管理 -->
<atguigu.spring.security.version>4.2.10.RELEASE</atguigu.spring.security.version>
</properties>
- 依赖管理
<dependencyManagement>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${atguigu.spring.version}</version>
</dependency>
</dependencyManagement>
2、Mybatis逆向工程
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.crowd</groupId>
<artifactId>atcrowdfunding06-common-reverse</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
</dependencies>
<!-- 控制 Maven 在构建过程中相关配置 -->
<build>
<!-- 构建过程中用到的插件 -->
<plugins>
<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<!-- 插件的依赖 -->
<dependencies>
<!-- 逆向工程的核心依赖 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2</version>
</dependency>
<!--MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
配置文件 generatorConfig.xml
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- mybatis-generator:generate -->
<context id="atguiguTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是;false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库连接的信息: 驱动类、 连接地址、 用户名、 密码 -->
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/project_crowd?serverTimezone=GMT"
userId="root"
password="136414">
</jdbcConnection>
<!-- 默认 false, 把 JDBC DECIMAL 和 NUMERIC 类型解析为 Integer, 为 true 时把
JDBC DECIMAL
和 NUMERIC 类型解析为 java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- targetProject:生成 Entity 类的路径 -->
<javaModelGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.entity">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- targetProject:XxxMapper.xml 映射文件生成的路径 -->
<sqlMapGenerator targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.mapper">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- targetPackage: Mapper 接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetProject=".\src\main\java"
targetPackage="com.atguigu.crowd.mapper">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- 数据库表名字和我们的 entity 类对应的映射指定 -->
<table tableName="t_admin" domainObjectName="Admin"/>
</context>
</generatorConfiguration>
3、Spring整合Mybatis
- 目标:adminMapper 通过 IOC 容器装配到当前组件中后,就可以直接调用它的方法,享受 到框架给我们提供的方便
- 思路
- 代码
在子工程中加入搭建环境所需要的具体依赖
<!--MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--MyBatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<!--MyBatis 与 Spring 整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
准备 jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/project_crowd?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT
jdbc.username=root
jdbc.password=136414
创建 Spring 配置文件专门配置 Spring 和 MyBatis 整合相关
spring-persist-mybatis.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 加载外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
<!-- 配置SqlSessionFactoryBean整合MyBatis -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定MyBatis全局配置文件位置 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
<!-- 指定Mapper.xml配置文件位置 -->
<property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/>
<!-- 装配数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置MapperScannerConfigurer来扫描Mapper接口所在的包 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.atguigu.crowd.mapper"/>
</bean>
</beans>
4、Spring整合SpringMVC
- 启动过程
- 环境搭建
加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="4.0"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
<!-- 配置 ContextLoaderListener 加载 Spring 配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-persist-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置 CharacterEncodingFilter 解决 POST 请求的字符乱码问题 -->
<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>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 强制响应进行编码 -->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置 SpringMVC 的前端控制器 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 以初始化参数的形式指定 SpringMVC 配置文件的位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-web-mvc.xml</param-value>
</init-param>
<!-- 让 DispatcherServlet 在 Web 应用启动时创建对象、初始化 -->
<!-- 默认情况:Servlet 在第一次请求的时候创建对象、初始化 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--MapallrequeststotheDispatcherServletforhandling-->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!--DispatcherServlet 映射的 URL 地址 -->
<!-- 大白话:什么样的访问地址会交给 SpringMVC 来处理 -->
<!-- 配置方式一:符合 RESTFUL 风格使用“/”-->
<!--<url-pattern>/</url-pattern>-->
<!-- 配置方式二:请求扩展名 -->
<url-pattern>*.html</url-pattern>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
</web-app>
- 异常映射
-
作用
统一管理项目中的异常
抛出异常
显示异常信息
-
普通请求:在页面上显示异常信息
-
Ajax 请求:返回 JSON 数据
-
-
异常映射的工作机制
创建异常处理器类、异常处理器类代码(优化后)
package com.atguigu.crowd.mvc.config;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.exception.AccessForbiddenException;
import com.atguigu.crowd.exception.LoginFailedException;
import com.atguigu.crowd.util.CrowdUtil;
import com.atguigu.crowd.util.ResultEntity;
import com.google.gson.Gson;
// @ControllerAdvice表示当前类是一个基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {
// @ExceptionHandler将一个具体的异常类型和一个方法关联起来
private ModelAndView commonResolve(
// 异常处理完成后要去的页面
String viewName,
// 实际捕获到的异常类型
Exception exception,
// 当前请求对象
HttpServletRequest request,
// 当前响应对象
HttpServletResponse response) throws IOException {
// 1.判断当前请求类型
boolean judgeResult = CrowdUtil.judgeRequestType(request);
// 2.如果是Ajax请求
if(judgeResult) {
// 3.创建ResultEntity对象
ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
// 4.创建Gson对象
Gson gson = new Gson();
// 5.将ResultEntity对象转换为JSON字符串
String json = gson.toJson(resultEntity);
// 6.将JSON字符串作为响应体返回给浏览器
response.getWriter().write(json);
// 7.由于上面已经通过原生的response对象返回了响应,所以不提供ModelAndView对象
return null;
}
// 8.如果不是Ajax请求则创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 9.将Exception对象存入模型
modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
// 10.设置对应的视图名称
modelAndView.setViewName(viewName);
// 11.返回modelAndView对象
return modelAndView;
}
}
基于注解的异常映射配置
<!-- 配置基于XML的异常映射 -->
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置异常类型和具体视图页面的对应关系 -->
<property name="exceptionMappings">
<props>
<!-- key属性指定异常全类名 -->
<!-- 标签体中写对应的视图(这个值要拼前后缀得到具体路径) -->
<prop key="java.lang.Exception">system-error</prop>
<prop key="com.atguigu.crowd.exception.AccessForbiddenException">admin-login</prop>
</props>
</property>
</bean>
<!-- 配置view-controller,直接把请求地址和视图名称关联起来,不必写handler方法了 -->
<!--
@RequestMapping("/admin/to/login/page.html")
public String toLoginPage(){
return "admin-login";
}
-->
<mvc:view-controller path="/admin/to/login/page.html" view-name="admin-login"/>
<mvc:view-controller path="/admin/to/main/page.html" view-name="admin-main"/>
- 拦截器
拦截器配置
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- mvc:mapping配置要拦截的资源 -->
<!-- /*对应一层路径,比如:/aaa -->
<!-- /**对应多层路径,比如:/aaa/bbb或/aaa/bbb/ccc或/aaa/bbb/ccc/ddd -->
<mvc:mapping path="/**"/>
<!-- mvc:exclude-mapping配置不拦截的资源 -->
<mvc:exclude-mapping path="/admin/to/login/page.html"/>
<mvc:exclude-mapping path="/admin/do/login.html"/>
<mvc:exclude-mapping path="/admin/do/logout.html"/>
<!-- 配置拦截器类 -->
<bean class="com.atguigu.crowd.mvc.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器类
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}
5、日志系统
- 重要意义:系统在运行过程中出了问题就需要通过日志来进行排查,所以我们在上手任何新技 术的时候,都要习惯性的关注一下它是如何打印日志的。
- 技术选型
- 不同日志系统的整合
- 更换框架的日志系统
第一步:排除 commons-logging
<dependecies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependecies>
第二步:加入转换包
<dependecies>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!-- 其他日志框架的中间转换包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
</dependecies>
第三步:logback 配置文件
<configuration debug="true"> <!-- 指定日志输出的位置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体 内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR-->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="INFO">
<!-- 指定打印日志的 appender,这里通过“STDOUT”引用了前面配置的 appender-->
<appender-ref ref="STDOUT"/>
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>
6、统一规范
- test范围是指测试范围有效,在编译和打包时都不会使用这个依赖
- compile范围是指编译范围内有效,在编译和打包时都会将依赖存储进去
- provided依赖,在编译和测试过程中有效,最后生成的war包时不会加入 例如: servlet-api,因为servlet-api tomcat服务器已经存在了,如果再打包会冲突
- runtime在运行时候依赖,在编译时候不依赖
- 默认依赖范围是compile
- 封装Ajax同意返回数据
package com.atguigu.crowd.util;
/**
* 统一整个项目中Ajax请求返回的结果(未来也可以用于分布式架构各个模块间调用时返回统一类型)
* @author Lenovo
*
* @param <T>
*/
public class ResultEntity<T> {
public static final String SUCCESS = "SUCCESS";
public static final String FAILED = "FAILED";
// 用来封装当前请求处理的结果是成功还是失败
private String result;
// 请求处理失败时返回的错误消息
private String message;
// 要返回的数据
private T data;
/**
* 请求处理成功且不需要返回数据时使用的工具方法
* @return
*/
public static <Type> ResultEntity<Type> successWithoutData() {
return new ResultEntity<Type>(SUCCESS, null, null);
}
/**
* 请求处理成功且需要返回数据时使用的工具方法
* @param data 要返回的数据
* @return
*/
public static <Type> ResultEntity<Type> successWithData(Type data) {
return new ResultEntity<Type>(SUCCESS, null, data);
}
/**
* 请求处理失败后使用的工具方法
* @param message 失败的错误消息
* @return
*/
public static <Type> ResultEntity<Type> failed(String message) {
return new ResultEntity<Type>(FAILED, message, null);
}
public ResultEntity() {
}
public ResultEntity(String result, String message, T data) {
super();
this.result = result;
this.message = message;
this.data = data;
}
@Override
public String toString() {
return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
- 判断是否Ajax请求
public static boolean judgeRequestType(HttpServletRequest request) {
// 1.获取请求消息头
String acceptHeader = request.getHeader("Accept");
String xRequestHeader = request.getHeader("X-Requested-With");
// 2.判断
return (acceptHeader != null && acceptHeader.contains("application/json"))
||
(xRequestHeader != null && xRequestHeader.equals("XMLHttpRequest"));
}
essage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
* 判断是否Ajax请求
```java
public static boolean judgeRequestType(HttpServletRequest request) {
// 1.获取请求消息头
String acceptHeader = request.getHeader("Accept");
String xRequestHeader = request.getHeader("X-Requested-With");
// 2.判断
return (acceptHeader != null && acceptHeader.contains("application/json"))
||
(xRequestHeader != null && xRequestHeader.equals("XMLHttpRequest"));
}