SSM框架搭建Web项目
上一篇文章:SpringMVC搭建一个Web项目
log4j.xml配置详解:log4j.xml配置详解
本文可在上一篇文章基础上配置,这里我所使用的环境是jdk1.8和Tomcat9.0.12。
SSM(Spring+SpringMVC+MyBatis)框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容)。常作为数据源较简单的web项目的框架。
1.基础概念
Spring
Spring就像是整个项目中装配bean的大工厂,在配置文件中可以指定使用特定的参数去调用实体类的构造方法来实例化对象。也可以称之为项目中的粘合剂。Spring的核心思想是IoC(控制反转),即不再需要程序员去显式地new一个对象,而是让Spring框架帮你来完成这一切。
SpringMVC
SpringMVC在项目中拦截用户请求,它的核心Servlet即DispatcherServlet承担中介或是前台这样的职责,将用户请求通过HandlerMapping去匹配Controller,Controller就是具体对应请求所执行的操作。SpringMVC相当于SSH框架中struts。
MyBatis
mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。
页面发送请求给控制器,控制器调用业务层处理逻辑,逻辑层向持久层发送请求,持久层与数据库交互,后将结果返回给业务层,业务层将处理逻辑发送给控制器,控制器再调用视图展现数据。
2.项目搭建
2.1 项目目录结构
jar包链接地址:Jar包下载点我
完整目录结构
所需jar包
2.2 添加配置文件
按照2.1目录添加配置文件web.xml,spring-mvc.xml,applicationContext.xml,jdbc.properties,log4j.xml。jdbc.properties为连接数据库相关数据,log4j.xml为日志配置。
部分标签解释请看上一篇文章,本文中大部分解释请看代码。
2.2.1 添加web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>MyDemo</display-name>
<!-- 读取spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</context-param>
<!-- 读取log4j配置文件 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/config/log4j.xml</param-value>
</context-param>
<!-- 添加spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 添加日志监听器 -->
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!-- 配置DispatcherServlet -->
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- servlet配置文件的位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 拦截设置 -->
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring字符集过滤器 -->
<filter>
<filter-name>encoding</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>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<!--"/*"表示拦截所有的请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2.2.2 添加spring-mvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/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.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 自动扫描且只扫描@Controller -->
<context:component-scan base-package="cn.com.mydemo" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置视图解析器 如何把handler 方法返回值解析为实际的物理视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- jsp路径前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!-- jsp路径后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 注解驱动 -->
<mvc:annotation-driven/>
<!-- 拦截器配置,根据自身业务配置,若无需求可不配置 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.com.mydemo.interceptor.RequestMappingInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!-- 容器默认的DefaultServletHandler处理 所有静态内容与无RequestMapping处理的URL-->
<mvc:default-servlet-handler/>
<!-- SpringMVC上传文件时,需要配置MultipartResolver处理器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8" />
<!-- 指定所上传文件的总大小不能超过10485760000B。注意maxUploadSize属性的限制不是针对单个文件,而是所有文件的容量之和 -->
<property name="maxUploadSize" value="10485760000"></property>
<property name="maxInMemorySize" value="40960"></property>
</bean>
<!-- 静态资源映射 -->
<mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
</beans>
<context:component-scan>:配置自动扫描的包。默认情况下,context:component-scan查找使用构造型(stereotype)注解所标注的类,如@Component(组件),@Service(服务),@Controller(控制器),@Repository(数据仓库),并这些类注册为bean。
注1:在SpringMVC的配置中为了防止Spring重复创建同一个类的实例,一般会用到<context:component-scan>的两个子标签<context:include-filter>&&<context:exclude-filter>。
注2:在很多配置中一般都会把application.xml和spring-mvc.xml进行分开配置,这种配置可以他们保证各司其职,在web.xml的一般配置中spring-mvc.xml实例创建初始化是以DispatchServlet为入口,而application.xml实例创建初始化是以ContextLoadListener为入口的,容器的加载顺序: listener -> filter -> servlet ,所以spring容器先初始化,springmvc容器后初始化 。
<back-package>:标识了<context:component-scan>元素所扫描的包,可以使用一些通配符进行配置。
<context:include-filter>:用来告知哪些类需要注册成Spring Bean,使用type和expression属性一起协作来定义组件扫描策略。
注:对于<context:include-filter>标签来讲它会扫描基包下面所有spring注解的类,而不是仅仅扫描 @Controller 。这点需要非常的注意,这一般会导致一个常见的错误,那就是事务不起作用,补救的方法是添加 use-default-filters=“false”,实现扫描<context:component-scan>的包中只包含<context:include-filter>的包。
<context:exclude-filter>:用来告知哪些类不需要注册成Spring Bean。实现扫描<context:component-scan>的包中且不包含<context:exclude-filter>的包。
2.2.3 添加applicationContext.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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<description>spring配置</description>
<!-- 使用annotation 自动注册bean, 并保证@Required、@Autowired的属性被注入 -->
<context:component-scan base-package="cn.com.mydemo">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 数据库连接池 -->
<!-- 加载jdbc.prooerties配置文件中的数据库连接信息 -->
<context:property-placeholder location="/WEB-INF/config/jdbc.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${jdbc.pool.initialPoolSize}"/>
<property name="minIdle" value="${jdbc.pool.minPoolSize}"/>
<property name="maxActive" value="${jdbc.pool.maxPoolSize}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${jdbc.pool.maxIdleTime}"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.pool.checkoutTimeout}"/>
<!-- 配置监控统计拦截的filters:stat(监控)、wall(sql防火墙)、log4j(监控日志输出) -->
<property name="filters" value="wall,stat,log4j"/>
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:cn/com/mydemo/mapper/*.xml"/>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 ,自动扫描了所有的XxxxMapper.xml对应的mapper接口文件,只要Mapper接口类和Mapper映射文件对应起来就可以了-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.com.mydemo.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 配置事务管理器,对dataSource 数据源进行事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 启用对事务注解的支持 -->
<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
2.2.4 添加jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
jdbc.pool.initialPoolSize=10
jdbc.pool.minPoolSize=5
jdbc.pool.maxPoolSize=40
jdbc.pool.maxIdleTime=20
jdbc.pool.checkoutTimeout=10000
2.2.5 添加log4j.xml配置文件
log4j.xml配置详解:log4j.xml配置详解
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--#log4j中有5级logger ,#FATAL 0 ,#ERROR 3 ,#WARN 4 ,#INFO 6 ,#DEBUG 7 -->
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j">
<!--输出到控制台-->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<!-- 日志输出格式 -->
<layout class="org.apache.log4j.TTCCLayout"/>
</appender>
<!-- 输出日志到文件,当文件大小达到一定阈值时,自动备份 -->
<appender name="rollingAppender" class="org.apache.log4j.RollingFileAppender">
<!-- 文件文件全路径名 -->
<param name="File" value="${catalina.base}/logs/demo/RollingFileAppender.log"/>
<!-- 是否在已存在的文件追加写:默认时true,若为false则每次启动都会删除并重新新建文件-->
<param name="Append" value="true"/>
<!-- 保存备份日志的最大个数,默认值是:1 -->
<param name="MaxBackupIndex" value="10"/>
<!-- 设置当日志文件达到此阈值的时候自动回滚,单位可以是KB,MB,GB,默认单位是KB,默认值是:10MB -->
<param name="MaxFileSize" value="5120KB"/>
<!-- 设置日志输出的样式 -->
<layout class="org.apache.log4j.PatternLayout">
<!-- 日志输出格式 -->
<param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%-5p] [method:%l]%n%m%n%n"/>
</layout>
</appender>
<!-- 日志输出到文件,可以配置多久产生一个新的日志信息文件 -->
<appender name="dailyRollingAppender" class="org.apache.log4j.DailyRollingFileAppender">
<!-- 文件文件全路径名 -->
<param name="File" value="${catalina.base}/logs/demo/DailyRollingFileAppender.log"/>
<param name="Append" value="true"/>
<param name="Threshold" value="DEBUG" />
<!-- 设置日志备份频率,默认:为每天一个日志文件 -->
<param name="DatePattern" value="yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%p][%d{HH:mm:ss SSS}][%c]-[%m]%n"/>
</layout>
</appender>
<!-- 下面这些就是根据 这些路径来控制对应包下的文件的日志输出级别,基本上都是报错了,才输出日志 -->
<logger name="org.apache.commons" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dailyRollingAppender"/>
</logger>
<logger name="org.mybatis.spring" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dailyRollingAppender"/>
</logger>
<logger name="java.sql" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dailyRollingAppender"/>
</logger>
<logger name="org.apache.ibatis" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dailyRollingAppender" />
</logger>
<logger name="org.springframework" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dailyRollingAppender"/>
</logger>
<logger name="com.mchange.v2" additivity="false">
<level value="ERROR"/>
<appender-ref ref="dailyRollingAppender"/>
</logger>
<logger name="com.alibaba.druid.filter.stat" additivity="false">
<level value="WARN"/>
<appender-ref ref="fileAppender"/>
</logger>
<logger name="com.alibaba.druid.pool" additivity="false">
<level value="WARN"/>
<appender-ref ref="fileAppender"/>
</logger>
<logger name="druid.sql.Connection" additivity="false">
<level value="WARN"/>
<appender-ref ref="fileAppender"/>
</logger>
<logger name="druid.sql.DataSource" additivity="false">
<level value="WARN"/>
<appender-ref ref="fileAppender"/>
</logger>
<logger name="druid.sql.ResultSet" additivity="false">
<level value="WARN"/>
<appender-ref ref="fileAppender"/>
</logger>
<logger name="druid.sql.Statement" additivity="false">
<level value="WARN"/>
<appender-ref ref="fileAppender"/>
</logger>
<!-- 根logger的设置,若代码中未找到指定的logger,则会根据继承机制,使用根logger-->
<root>
<appender-ref ref="console"/>
<appender-ref ref="fileAppender"/>
<appender-ref ref="rollingAppender"/>
<appender-ref ref="dailyRollingAppender"/>
</root>
</log4j:configuration>
2.3 添加Controller,Service,Dao,Mapper,Model,Jsp等文件
2.3.1 新建LoginController.java
package cn.com.mydemo.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.com.mydemo.model.User;
import cn.com.mydemo.service.LoginService;
/**
* @Description 登录Controller
* @author jjy
* @Creation 2019-02-21
*/
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
private static Logger log = LoggerFactory.getLogger(LoginController.class);
/**
* @Description 初始化登录页面
* @param model
* @return
* @Creation 2019-02-21 by jjy
*/
@RequestMapping(value = "/")
public String init(Model model) {
User us = new User("1");
log.debug("搜索用户id为1的用户信息");
User user = loginService.selectByID(us);
model.addAttribute("id", user.getId());
model.addAttribute("name", user.getName());
return "login";
}
}
@Autowired:自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property,当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。在application.xml配置为<context:component-scan base-package=“cn.com.mydemo” />。
2.3.2 新建LoginService.java
package cn.com.mydemo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.com.mydemo.dao.LoginDao;
import cn.com.mydemo.model.User;
/**
* @Description 登录Service
* @author jjy
* @Creation 2019-02-21
*/
@Service
public class LoginService {
@Autowired
private LoginDao loginDao;
/**
* @Description 根据用户ID搜索用户
* @param user
* @return
* @Creation 2019-02-21 by jjy
*/
public User selectByID(User user) {
return loginDao.selectByID(user);
}
}
@Service:业务层的类注解。
2.3.3 新建User.java
package cn.com.mydemo.model;
/**
* @Description 用户实体
* @author jjy
* @Creation 2019-02-21
*/
public class User {
private String id;
private String name;
public User() {
}
public User(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.3.4 新建LoginDao.java
package cn.com.mydemo.dao;
import cn.com.mydemo.model.User;
/**
* @Description 登录Dao
* @author jjy
* @Creation 2019-02-21
*/
public interface LoginDao {
User selectByID(User user);
}
2.3.5 新建LoginDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.com.mydemo.dao.LoginDao">
<select id="selectByID" parameterType="cn.com.mydemo.model.User" resultType="cn.com.mydemo.model.User">
SELECT ID,NAME FROM USER WHERE ID = #{id}
</select>
</mapper>
2.3.5 新建login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<label>用户id:${id}</label><br>
<label>用户名:${name}</label>
</body>
</html>
2.4 运行及结果
数据库数据
页面
控制台日志信息