**
一、Spring整合Mybatis
1. 思维导图
2.操作清单
在子工程中加入搭建环境所需要的具体依赖 准备 jdbc.properties 创建 Spring 配置文件专门配置 Spring 和 MyBatis 整合相关 在 Spring 的配置文件中加载 jdbc.properties 属性文件 配置数据源 测试从数据源中获取数据库连接 配置 SqlSessionFactoryBean 装配数据源 指定 XxxMapper.xml 配置文件的位置 指定 MyBatis 全局配置文件的位置(可选) 配置 MapperScannerConfigurer 测试是否可以装配 XxxMapper 接口并通过这个接口操作数据库
二、日志系统
1. 重要意义
系统在运行过程中出了问题就需要通过日志来进行排查,所以我们在上手任何新技 术的时候,都要习惯性的关注一下它是如何打印日志的。
2.具体操作
把spring自带的日志系统的包排除 commons-logging 那么就必须要有一个包代替他不然执行了打印日志操作
加入 slf4j+logback 这个包相当于是代替了commons-logging
加入转换包
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
3.我们主动打印的日志
※使用日志打印信息和使用 sysout 打印信息的区别:sysout 如果不删除,那么 执行到这里必然会打印;如果使用日志方式打印,可以通过日志级别控制信息是否打印 IO流影响效率在实际开发中
4.logback 配置文件–名字必须是logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
三、声明事务
1.目标
从事务角度:一个事务方法中包含的多个数据库操作,要么一起提交、要么一起回 滚。也就是说事务方法中的多个数据库操作,有任何一个失败,整个事务全部回滚。 从声明式角度:由 Spring 来全面接管数据库事务。用声明式代替编程式。
2.思路
3.代码
spring-persist-tx.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: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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:component-scan base-package="com.atguigu.crowd.service" />
<!-- 配置事务管理器 -->
<bean
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="dataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置aop 事务切面 -->
<aop:config>
<aop:pointcut expression="execution(* *..*ServiceImpl.*(..))"
id="txPointcut" />
<!-- 将切入点表达式和事务通知关联起来 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<!-- 查询方法 只读属性 优化 性能更好 -->
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="count*" read-only="true" />
<!-- 增删改方法另外配置 -->
<!-- propagation 属性配置事务方法的传播行为 -->
<!-- 默认值:REQUIRED 表示:当前方法必须运行在事务中,如果没有事务,则开 启事务,在自己的事务中运行。如果已经有了已开启的事务,则在当前事务中运行。有可能 和其他方法共用同一个事务。 -->
<!-- 建议值:REQUIRES_NEW 表示:当前方法必须运行在事务中,如果没有事务, 则开启事务,在自己的事务中运行。和 REQUIRED 的区别是就算现在已经有了已开启的事务, 也一定要开启自己的事务,避免和其他方法共用同一个事务。 -->
<!-- rollback-for 属性配置回滚的异常 --> <!-- 默认值:运行时异常 --> <!-- 建议值:编译时异常+运行时异常 -->
<tx:method name="save*" propagation="REQUIRES_NEW"
rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRES_NEW"
rollback-for="java.lang.Exception" />
<tx:method name="remove*" propagation="REQUIRES_NEW"
rollback-for="java.lang.Exception" />
<tx:method name="batch*" propagation="REQUIRES_NEW"
rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice>
</beans>
错误点
1.No qualifying bean of type vailable: expected at least 1 bean which qualifies as autowire
包扫描不对 仔细检查
四、表现层
1.表现层机制
2.在web.xml配置1 ContextLoaderListener
作用:加载 Spring 的配置文件,根据 Spring 的配置文件初始化 IOC 容器
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-persist-*.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3.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>
<!-- request.setCharacterEncoding(encoding) 要 求 必 须 在 所 有request.getParameter(xxx)操作前面
response.setCharacterEncoding(encoding)要求必须在所有 response.getWriter()
操作前面不满足这个顺序要求字符集设定无法生效 -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.配置DispatcherServlet
<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>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
5.请求扩展名
html扩展名
举例http://localhost:8080/atcrowdfunding02-admin-webui/save/emp.html 作用:伪静态 表面上看起来是一个访问静态资源的请求,但是实际上是由 SpringMVC 交给 handler 来处理的动态资源。
好处 1:有利于 SEO 优化 让搜索引擎更容易找到我们的网站,有利于网站的推广
好处 2:隐藏后端技术实现细节 给黑客入侵系统增加难度 好处 3:自动解决静态资源访问问题 访问 a.png 本身不符合.html 这个 url-pattern,和 SpringMVC 完全没 有关系,当前请求由 Tomcat 处理。 如 果 url-pattern 映 射 了 “ / ”, 那 么 SpringMVC 中 还 需 要 配 置 DefaultServletHandler。 缺陷:不符合 RESTFUL 风格*
json扩展名
描述问题 请求扩展名 http://localhost:8080/extra01-ajax/get/emp/by/ajax.html 服务器端打算返回的数据:JSON 格式 二者不匹配!!!
分析问题 请求扩展名和响应体的数据格式不匹配!!!
解决问题
让请求扩展名和预计的响应体数据格式一致。
http://localhost:8080/extra01-ajax/get/emp/by/ajax.json 同时让 SpringMVC 在映射*.html 扩展名之外再映射*.json 扩展名,不然会 返回 404
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
6.配置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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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:component-scan base-package="com.atguigu.crowd.mvc" />
<!-- 配置springmvc注解驱动 -->
<mvc:annotation-driven />
<!-- 配置是视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
7.base标签
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath }/">
base 标签必须写在 head 标签内部
base 标签必须在所有“带具体路径”的标签的前面
serverName 部分 EL 表达式和 serverPort 部分 EL 表达式之间必须写“:”
serverPort 部分 EL 表达式和 contextPath 部分 EL 表达式之间绝对不能“/”
原因:contextPath 部分 EL 表达式本身就是“/”开头 如果多写一个“/”会干扰 Cookie 的工作机制 serverPort 部分 EL 表达式后面必须写“/”
五.@ResponseBody 注解
ajax请求路线图形:
作用
让 handler 方法的返回值本身就是当前请求的响应数据。不再参考视图处理器 中配置的前后缀信息。
注意
开启 SpringMVC 的注解驱动 mvc:annotation-driven/
必须有 jackson 依赖 jackson-core jackson-databind
扩展名需要和实际返回的数据格式一致 响应体返回 JSON 请求扩展名*.json web.xml 中
@RequestParam
后台接受数据
index.jsp 页面代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
$("#btn3").click(function() {
var array=[5,8,12];
//将json数组转为json字符串
var requestBody=JSON.stringify(array);
$.ajax({
"url" : "send/array3.html",
"type" : "post",
"data" : requestBody,
"contentType" :"application/json;charset=UTF-8 ", //告诉 请求体的内容类型,告诉服务器本次请求的请求体是JSON数据
"dataType" : "text",
"success" : function(response) {
alert(response);
},
"error" : function(response) {
alert(response);
}
});
});
$("#btn1").click(function() {
$.ajax({
"url" : "send/array.html",
"type" : "post",
"data" : {
"array" : [ 5, 8, 12 ]
},
"dataType" : "text",
"success" : function(response) {
alert(response);
},
"error" : function(response) {
alert(response);
}
});
});
});
</script>
<!-- http://localhost:8080/atcrowdfunding02-admin-webui/test/ssm.html -->
<base
href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath }/">
</head>
<body>
<a href="test/ssm.html">测试ssm环境</a>
<br>
<button id="btn1">Send数组【5,8,12】</button>
<br>
<button id="btn3">Send3数组【5,8,12】</button>
</body>
</html>
特别注意第三种ajax请求 要把数组转为JSON字符串
写上contentType:“contentType” :"application/json;charset=UTF-8 ", //告诉 请求体的内容类型,告诉服务器本次请求的请求体是JSON数据
Handler接受json用@requestBody接受
@ResponseBody
@RequestMapping("/send/array3.html")
public String sendoneajax3(@RequestBody List<Integer> array){
Logger logger= LoggerFactory.getLogger(TestHandler.class);
for (Integer number : array) {
logger.info("number="+number);
}
return "success";
}
统一返回数据格式
package com.hp.crowd.utils;
/**
* 统一整个项目中Ajax请求返回的结果(未来也可以用来分布式架构各个模块调用时的返回类型)
* @author SX
*
* @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);
}
/**
* 请求处理成功且需要返回数据时的工具方法
* 要返回的数据
* @return
*/
public static <Type> ResultEntity<Type> successWithData(Type data) {
return new ResultEntity<Type>(SUCCESS, null, data);
}
/**
* 请求处理失败返回错误信息的工具栏
*
* @return
*/
public static <Type> ResultEntity<Type> failed(String message) {
return new ResultEntity<Type>(FAILED, message, null);
}
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;
}
@Override
public String toString() {
return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
}
public ResultEntity(String result, String message, T data) {
super();
this.result = result;
this.message = message;
this.data = data;
}
public ResultEntity() {
super();
// TODO Auto-generated constructor stub
}
}
异常映射
13.1作用 统一管理项目中的异常
抛出异常
显示异常信息
普通请求:在页面上显示异常信息
Ajax 请求:返回 JSON 数据
13.2异常映射的工作机制
13.3基于xml的异常映射
<!-- 配置基于xml的异常映射机制 -->
<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置异常类型和具体视图页面的对应关系 -->
<property name="exceptionMappings">
<props>
<!-- key属性指定 异常类型全类名 -->
<!-- 标签体中写对应的视图(这个值要拼前后缀得到具体路径) -->
<prop key="java.lang.Exception">system-error</prop>
</props>
</property>
</bean>
写一个错误返回页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>出错了!</h1>
<!--从请求域中取出exception对象,在进一步访问message属性就能显示错误 -->
${requestScope.exception.message}
</body>
</html>
13.4判断请求类型工具方法
导入servletapi
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
创建工具类编写工具方法
package com.hp.crowd.utils;
import javax.servlet.http.HttpServletRequest;
public class CrowdUtil {
/**
* 判断当前请求是否为Ajax请求
*
* @param request
* 请求对象
* @return true:当前请求是Ajax请求 false:当前请求不是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"));
}
}
13.5异常处理器类
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;
/**
* 基于注解的异常处理器类
* @author SX
*
*/
//@ControllerAdvice 表示当前类是一个处理异常的类
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import com.google.gson.Gson;
import com.hp.crowd.utils.CrowdUtil;
import com.hp.crowd.utils.ResultEntity;
@ControllerAdvice
public class CrowdExceptionResolver {
@ExceptionHandler(value = ArithmeticException.class)
public ModelAndView resolveMathException(ArithmeticException exception,
// 当前请求对象
HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "system-error";
return commonResolve(viewName, exception, request, response);
}
// @ExceptionHandler将一个具体的异常类型和一个方法关联起来
@ExceptionHandler(value = NullPointerException.class)
public ModelAndView resolveLoginFailedException(
// 实际捕获异常参数类型
NullPointerException exception,
// 当前请求对象
HttpServletRequest request, HttpServletResponse response) throws IOException {
String viewName = "system-error";
return commonResolve(viewName, exception, request, response);
}
public 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.转为json
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("exception", exception);
// 10设置对应的视图名称
modelAndView.setViewName("system-error");
// 10:返回modelAndView对象
return modelAndView;
}
}
14 以常量管理属性名和异常消息
package com.hp.crowd.constant;
public class CrowdConstant {
public static final String MESSAGE_LOGIN_FAILED = "抱歉!账号密码错误!请重新输入!";
public static final String MESSAGE_LOGIN_ACCT_ALREADY_IN_USE = "抱歉!这个账号已经被使用了!";
public static final String MESSAGE_ACCESS_FORBIDEN = "请登录以后再访问!";
public static final String MESSAGE_STRING_INVALIDATE = "字符串不合法!请不要传入空字符串!";
public static final String MESSAGE_SYSTEM_ERROR_LOGIN_NOT_UNIQUE = "系统错误:登录账号不唯一!";
public static final String ATTR_NAME_EXCEPTION = "exception";
public static final String ATTR_NAME_LOGIN_ADMIN = "loginAdmin";
public static final String ATTR_NAME_PAGE_INFO = "pageInfo";
}
前端页面
引入静态资源
调整部分文件代码
<meta name="keys" content="">
<meta name="author" content="">
<base
href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath }/">
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/login.css">
<script src="jquery/jquery-2.1.1.min.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
12.2.3配置 view-controller
<mvc:view-controller path="/admin/to/login/page.html" view-name="admin-login"/>
12.3layer 弹层组件
引入layer库
在jsp层引入js
<script type="text/javascript" src="layer/layer.js"></script>
异常处理页面的返回上一步js
<script type="text/javascript">
$(function(){
//相当于window的返回上一步
$("button").click(function(){
window.history.back();
});
})
</script>