介绍
学习笔记的形式以一个项目实践为引子,将所有开发过程详细的整理出来,同时指出过程中的错误,以及每个阶段对于这些内容使用的感悟,希望这是一个好的开始。
首先,本次笔记中的项目所使用的技术包括:SSM(Spring MVC+Spring+MyBatis)、FTL页面、layui、Oracle数据库、druid数据库连接池
数据库脚本
CREATE TABLE p_booktype(
type_id number(10) primary key, --类型ID
type_name varchar2(255) --类型名称
);
CREATE TABLE p_bookpress(
press_id number(10) primary key, --出版社ID
press_name varchar2(255) --出版社名称
);
CREATE TABLE p_area(
area_id number(10) primary key, --地区ID
area_title varchar2(1000), --地区名称
area_parid number(10) --地区的父ID
);
CREATE TABLE t_user(
userid number(10) primary key,
username varchar2(100),
userpwd varchar2(200)
);
CREATE TABLE p_book(
book_id number(10) primary key, --书籍ID
book_name varchar2(255), --书籍名称
book_author varchar2(255), --书籍作者
book_cover varchar2(255), --书籍封面
book_price number(10,2), --书籍价格
book_type_id number(10), --书籍类型ID
book_press_id number(10), --书籍出版社ID
book_status number(10), --书籍状态
book_label varchar2(255), --书籍标签
book_desc varchar2(2000), --书籍描述
author_proId number(10), --作者省ID
author_cityId number(10), --作者市ID
book_add_time date, --书籍出版时间
book_userid number(10), --操作用户
constraint fk_tpid foreign key(book_type_id) references p_booktype(type_id),
constraint fk_ptid foreign key(book_press_id) references p_bookpress(press_id),
constraint fk_prid foreign key(author_proId) references p_area(area_id),
constraint fk_ctid foreign key(author_cityId) references p_area(area_id)
);
搭建项目环境
1、建立开发的包结构
src: |-cn.mldn.szq |-controller:控制层 |-service:业务层 |-mapper:数据层 |-model:实体层 |-util:工具包 |-mapper:存放mybatis编写SQL的映射文件 |-book-mapper.xml |-相应的配置文件 webRoot: |-plugins:存放页面使用的插件 |-upload:存放上传的图片 |-templates:所有的页面(页面的以".ftl"结尾) |-WEB-INFO |-lib |-web.xml |
2、导入相关的jar包并配置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_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>ssm-book-szq</display-name>
<!-- 配置springmvc前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载配置文件(spring-mvc.xml) -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-mvc.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<!-- 字符集过滤,解决中文乱码 -->
<filter>
<filter-name>encodingFilter</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>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置spring监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 加载核心配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml,
classpath:spring-mybatis.xml,
</param-value>
</context-param>
<!-- 配置log4j监听 -->
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<!-- 加载log4j配置文件 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<!-- 定义扫描文件的时间 -->
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>3000</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
对于web.xml文件配置过程中的理解:
在web.xml文件中配置的内容就是在项目启动时就需要加载的内容,比如各个框架的配置文件等。而要注意的是在配置spring-mvc时所设置的映射路径,本次设置的是“/*”,代表的就是对所有的请求路径都会进行进入到DispatcherServlet中进行处理,所以在后面的页面访问中,如果需要引入静态资源,还需要专门在Spring-mvc.xml文件中进行资源释放。 |
3、配置spring-mvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"
>
<!-- 开启注解模式,扫描controller包下的所有子包中的所有类,
凡是包含@Controller注解的类都会生成控制层实例 -->
<context:component-scan base-package="cn.mldn.szq.controller" />
<mvc:annotation-driven/>
<!-- freemarker视图解析器 -->
<bean id="FreeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/templates/"/><!--此为文件的前缀-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="FreeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="suffix" value=".ftl"/><!--文件的后缀-->
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="requestContextAttribute" value="request" />
<property name="order" value="1"/>
<property name="cache" value="false" />
</bean>
<!--上文件上传解析-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--文件的最大上传大小:单位(byte:字节)-->
<property name="maxUploadSize" value="20480000"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
<!-- 静态资源过滤 -->
<mvc:resources location="/plugins/" mapping="/plugins/**"/>
<mvc:resources location="/upload/" mapping="/upload/**"/>
</beans>
对于spring-mvc.xml文件的理解
控制层的作用有: ·接收并处理发送来的请求 ·控制数据的流动,获取并处理前后台处理的数据 ·负责页面的跳转 基于上面的理解,所以在控制层的配置文件,首先需要引入控制层的处理路径,以及视图解析器,上传文件的配置,以及对于请求的一些静态资源进行释放,还可以配置用户自定义的拦截器等 |
3、本次druid数据库连接池,对于连接池的配置采用资源文件方式:datasource.properties
c3p0.orcl.info.url=jdbc:oracle:thin:@localhost:1521:mldn
c3p0.orcl.info.username=cht
c3p0.orcl.info.password=123
而后在spring的第一个文件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.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"
default-autowire="byName"
default-lazy-init="false">
<!-- 开启注解模式 扫描com.jk下的任意子包中的任意类
凡是包含:Controller、Service、Repository、Autowired这些注解的类都会被发现 -->
<context:component-scan base-package="cn.mldn.szq.service"></context:component-scan>
<!-- 加载properties文件 -->
<context:property-placeholder location="classpath:datasource.properties" />
</beans>
然后在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: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/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"
default-lazy-init="false">
<!-- 配置数据库连接池(druid:alibaba) -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="url" value="${c3p0.orcl.info.url}" />
<property name="username" value="${c3p0.orcl.info.username}" />
<property name="password" value="${c3p0.orcl.info.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' from dual" />
<!-- 当连接空闲的时候测试 -->
<property name="testWhileIdle" value="true" />
<!-- 连接被借用的时候测试 -->
<property name="testOnBorrow" value="true" />
<!-- 连接被归还的时候测试 -->
<property name="testOnReturn" value="true" />
<!-- 开启监控功能 -->
<!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
<property name="filters" value="stat" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置实体类扫描路径 -->
<property name="typeAliasesPackage" value="cn.mldn.szq.model" />
<!-- 加载mybatis核心配置文件 -->
<property name="configLocation" value="classpath:mybatis.cfg.xml"/>
<!-- 配置映射文件扫描路径 -->
<property name="mapperLocations" value="classpath:mapper/**/*-mapper.xml" />
</bean>
<!-- Transaction manager for a single JDBC DataSource -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 配置dao接口扫描路径 -->
<property name="basePackage" value="cn.mldn.szq.mapper" />
</bean>
<!-- 配置事务传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"
read-only="true" />
<tx:method name="update*" propagation="REQUIRED"
read-only="true"/>
<tx:method name="delete*" propagation="REQUIRED"
read-only="true" />
<tx:method name="get*" propagation="REQUIRED"
read-only="true"/>
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!--advice-ref:引入第二步中的传播特性 -->
<aop:advisor pointcut="execution (* cn.mldn.szq.service..*.*(..))"
advice-ref="txAdvice" />
</aop:config>
</beans>
对于这部分配置的理解:
在三大框架中,目前我所接触的spring的功能主要是DI,AOP,ORM,过去的数据库打开关闭,实体类对象的创建以及事务的提交回滚都集中在了业务层进行处理,这也是在框架发展中出现的弊病,所以Spring就承担了所有非核心业务的其他操作。 所以在我的理解中spring的配置文件一般会配置:需要spring管理的类路径(dao,service),数据库的操作(一般以资源文件导入数据库的配置)处理中使用数据库连接池,所以可以配置连接池的参数来管理数据库的操作,而此时配置好的也就是数据源,当有了数据源之后需要配置的就是何时去连接数据库,也就是sqlSessionFactory的配置,以及对于数据库的操作中的事务管理,并且配置好AOP。 而这些配置中我发现AOP的配置并不像HIbernate中配置的那么强制性,如果没有配置好相应的方法,在MyBatis并不会报错,而且可以继续执行,只不过不能进行正确的事务回滚,这里不太理解。并且对于SqlSessionFactory以及事务管理配置的数据源还是不太清楚 |
因为默认mybatis并不会进行日志输出,所以还需要配置log4j.properties文件
#ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF
log4j.rootLogger = debug,stdout,E,E
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://my-logs/debug.log
#log4j.appender.D.File = /opt/logs/my-logs/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.DatePattern='_'yyyy-MM-dd-HH-mm'.log'
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://my-logs/error.html
#log4j.appender.E.File = /opt/logs/my-logs/error.html
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.DatePattern='_'yyyy-MM-dd-HH-mm'.html'
log4j.appender.E.layout = org.apache.log4j.HTMLLayout
#log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
#log4j.logger.com.ibatis = debug
#log4j.logger.com.ibatis.common.jdbc.SimpleDataSource = debug
#log4j.logger.com.ibatis.common.jdbc.ScriptRunner = debug
#log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate = debug
#log4j.logger.java.sql.Connection = debug
#log4j.logger.java.sql.Statement = debug
#log4j.logger.java.sql.PreparedStatement = debug
#log4j.logger.java.sql.ResultSet =debug
log4j.logger.com.demo.mapper =debug
而我对于该文件压根就没不懂其结构。配置好此处之后,还需要其与mybatis进行管理,所以还需要有一个单独的mybatis.cfg.xml文件进行文件引入,并且对于一些进行参数的配置
<?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>
<!--<properties></properties>-->
<!-- mybatis属性设置 -->
<settings>
<setting name="logImpl" value="LOG4J"></setting>
<!--<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>-->
</settings>
<!--<typeAliases></typeAliases>-->
<!--<typeHandlers></typeHandlers>-->
<!--<objectFactory type=""/>-->
<!--<objectWrapperFactory type=""/>-->
<!--
plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 4.0.0以后版本可以不设置该参数 -->
<!-- <property name="dialect" value="oracle"/> -->
<!-- 该参数默认为false -->
<!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
<!-- 和startPage中的pageNum效果一样-->
<property name="offsetAsPageNum" value="true"/>
<!-- 该参数默认为false -->
<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
<property name="rowBoundsWithCount" value="true"/>
<!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
<!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型)-->
<property name="pageSizeZero" value="true"/>
<!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
<!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
<!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
<property name="reasonable" value="false"/>
<!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
<!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 -->
<!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默认值 -->
<!-- 不理解该含义的前提下,不要随便复制该配置 -->
<property name="params" value="pageNum=pageHelperStart;pageSize=pageHelperRows;"/>
<!-- 支持通过Mapper接口参数来传递分页参数 -->
<property name="supportMethodsArguments" value="false"/>
<!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
<property name="returnPageInfo" value="none"/>
</plugin>
</plugins>
</configuration>
而对于此处的分页处理,会在后面使用,但是发现其操作确实实用,但是对于其分页的处理,确实不太明白。
当以上的配置文件都处理好之后,就可以进行项目的开发了,而还有一个重要的配置文件,就是写每个实体类对应的数据库SQL语句处理。后面会进行相关的配置。
至此,项目环境搭建完毕!