1.新建一个Maven项目
这里以Idea工具为例,打开IDEA,然后File->New->Project ->Maven->Create from archetype。
2.在pom.xml中添加项目所需的依赖包
< ! -- SpringMVC,包含有spring-aop,spring-beans,spring-context,spring-core,springexpression,spring-web,spring-webmvc包 -->
< dependency>
< groupId> org.springframework< /groupId>
< artifactId> spring-webmvc< /artifactId>
< version> 4.3.14.RELEASE< /version>
< /dependency>
< ! -- Spring事务包 -->
< dependency>
< groupId> org.springframework< /groupId>
< artifactId> spring-tx< /artifactId>
< version> 4.3.14.RELEASE< /version>
< /dependency>
< dependency>
< groupId> org.springframework< /groupId>
< artifactId> spring-jdbc< /artifactId>
< version> 4.3.14.RELEASE< /version>
< /dependency>
< ! -- Spring事务包 --> < ! --AOP依赖包-->
< dependency>
< groupId> org.aspectj< /groupId>
< artifactId> aspectjrt< /artifactId>
< version> 1.9.2< /version>
< /dependency>
< dependency>
< groupId> org.aspectj< /groupId>
< artifactId> aspectjweaver< /artifactId>
< version> 1.9.2< /version>
< /dependency>
< ! --AOP依赖包--> < ! --AOP的CGLIB动态代理实现包-->
< dependency>
< groupId> cglib< /groupId>
< artifactId> cglib< /artifactId>
< version> 3.2.2< /version>
< /dependency>
< ! -- servlet-api -->
< dependency>
< groupId> javax.servlet< /groupId>
< artifactId> javax.servlet-api< /artifactId>
< version> 4.0.1< /version>
< scope> provided< /scope>
< /dependency>
< ! -- c3p0 数据库连接池 -->
< dependency>
< groupId> com.mchange< /groupId>
< artifactId> c3p0< /artifactId>
< version> 0.9.5.2< /version>
< /dependency>
< ! -- MySQL驱动包-->
< dependency>
< groupId> mysql< /groupId>
< artifactId> mysql-connector-java< /artifactId>
< version> 8.0.15< /version>
< /dependency>
< ! -- mybatis -->
< dependency>
< groupId> org.mybatis< /groupId>
< artifactId> mybatis< /artifactId>
< version> 3.4.1< /version>
< /dependency>
< dependency>
< groupId> org.mybatis< /groupId>
< artifactId> mybatis-spring< /artifactId>
< version> 1.3.0< /version>
< /dependency>
< ! -- mybatis -->
< ! -- Gson -->
< dependency>
< groupId> com.google.code.gson< /groupId>
< artifactId> gson< /artifactId>
< version> 2.8.5< /version>
< /dependency>
< ! -- SLF4J日志.注意版本问题,高版本与java8不兼容 -->
< dependency>
< groupId> org.slf4j< /groupId>
< artifactId> slf4j-api< /artifactId>
< version> 1.7.25< /version>
< /dependency>
< dependency>
< groupId> org.apache.logging.log4j< /groupId>
< artifactId> log4j-core< /artifactId>
< version> 2.9.1< /version>
< scope> runtime< /scope>
< /dependency>
< dependency>
< groupId> org.apache.logging.log4j< /groupId>
< artifactId> log4j-slf4j-impl< /artifactId>
< version> 2.9.1< /version>
< scope> runtime< /scope>
< /dependency>
< dependency>
< groupId> org.apache.logging.log4j< /groupId>
< artifactId> log4j-web< /artifactId>
< version> 2.9.1< /version>
< scope> runtime< /scope>
< /dependency>
< ! -- SLF4J日志结束 -->
< ! --高性能的异步处理框架,提高log4j2并发性能-->
< dependency>
< groupId> com.lmax< /groupId>
< artifactId> disruptor< /artifactId>
< version> 3.4.2< /version>
< scope> runtime< /scope>
< /dependency>
< ! -- LomBok,POJO管理框架-->
< dependency>
< groupId> org.projectlombok< /groupId>
< artifactId> lombok< /artifactId>
< version> 1.18.4< /version>
< scope> provided< /scope>
< /dependency>
3.新建类目录和资源目录
在src下面的main文件夹上右击,New->Directory,新建一个Java目录和一个resources目录。 然后在Java目录上右键,Mark Directory as -> Sources Root 接着在resources目录上右键,Mark Directory as -> Resources Root 最终效果如下图,注意java与resources文件夹的颜色与样式。 如果需要测试文件目录的,还可以在main目录下面创建一个test文件,然后右键test目录,Mark Directory as -> Test Sources Root,类似地,测试的资源目录也是一样,将其标记为Test Resources Root就可以了。
4.新建项目包结构
在java目录右击鼠标,New->Package,新建项目的包名,将需要用到的包名建好,一般是以公司或者组织的组织Id开头,然后在下面细分为controller,service,dao,bean,utils等子包。 项目包结构建好之后整个项目的目录结构如下图: PS:考虑到初学者可能无法顺利的创建出上面的包结构,这里给出一个小提示,如果要实现上图目录中的两个子包(比如controller和service)在同一级(同一父包,com.yixiaojun.ssdmdemo如)下,则需要在java文件目录下右键,然后输入两个包的全路径:
c
o
m
.
y
i
x
i
a
o
j
u
n
.
s
s
d
m
d
e
m
o
.
c
o
n
t
r
o
l
l
e
r
\color{blue}{com.yixiaojun.ssdmdemo.controller}
c o m . y i x i a o j u n . s s d m d e m o . c o n t r o l l e r ,
c
o
m
.
y
i
x
i
a
o
j
u
n
.
s
s
d
m
d
e
m
o
.
s
e
r
v
i
c
e
\color{green}{com.yixiaojun.ssdmdemo.service}
c o m . y i x i a o j u n . s s d m d e m o . s e r v i c e ,这样就可以出现两个子包在同一级下的效果了,然后就可以右键父包,输入其他子包的名字,从而创建出上图中的包结构了。
5.配置项目
当上面的任务都完成了之后,就可以对项目进行配置了,在进行配置之前,我们需要按照下图的文件结构创建几个文件夹和配置文件。
6.配置文件的内容如下
jdbc. driverClass= com. mysql. cj. jdbc. Driver
jdbc. url= jdbc: mysql: / / localhost: 3306 / sc?
serverTimezone= GMT% 2 B8& characterEncoding= utf- 8 & useSSL= true
jdbc. username= root
jdbc. password= 123456
jdbc. maxPoolSize= 100
jdbc. minPoolSize= 10
jdbc. initialPoolSize= 20
jdbc. maxIdleTime= 25000
jdbc. acquireIncrement= 5
jdbc. maxStatements= 5
jdbc. idleConnectionTestPeriod= 18000
jdbc.url后面的值需要换成自己的数据库地址,
j
d
b
c
.
u
s
e
r
n
a
m
e
\color{blue}{jdbc.username}
j d b c . u s e r n a m e 后面的值需要换成自己的数据库用户名,
j
d
b
c
.
p
a
s
s
w
o
r
d
\color{blue}{jdbc.password}
j d b c . p a s s w o r d 后面的值需要换成自己的用户密码。 web.xml
< ? xml version= "1.0" encoding= "UTF-8" ? >
< web- app 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"
version= "4.0" >
< ! -- 定义web应用的名称-- >
< display- name> ssmdemo< / display- name>
< ! -- 指定Spring上下文参数配置文件的路径-- >
< context- param>
< param- name> contextConfigLocation< / param- name>
< param- value> / WEB- INF/ spring/ spring- context. xml< / param- value>
< / context- param>
< ! -- Spring上下文监听器,用来加载Spring的上下文配置并初始化Spring -- >
< listener>
< description> 启动spring容器< / description>
< listenerclass>
org. springframework. web. context. ContextLoaderListener< / listener- class >
< / listener>
< ! -- LOG4J上下文监听器,用来加载LOG4J2的配置并初始化LOG4J -- >
< listener>
< listenerclass>
org. apache. logging. log4j. web. Log4jServletContextListener< / listener- class >
< / listener>
< ! -- 字符编码过滤器,将编码改为UTF- 8 -- >
< filter>
< filter- name> encodingFilter< / filter- name>
< filterclass>
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> encodingFilter< / filter- name>
< url- pattern>
< / filter- mapping>
< ! -- SpringMVC前置控制器,拦截匹配的请求,把拦截下来的请求,根据相应的规则分发到目标Controller来处理-- >
< servlet>
< servlet- name> spring- mvc< / servlet- name>
< servletclass>
org. springframework. web. servlet. DispatcherServlet< / servlet- class >
< ! -- 指定路径SpringMVC上下文配置路径-- >
< init- param>
< param- name> contextConfigLocation< / param- name>
< param- value> / WEB- INF/ spring/ spring- mvc. xml< / param- value>
< / init- param>
< ! -- 随web应用启动而启动 -- >
< load- on- startup> 1 < / load- on- startup>
< / servlet>
< servlet- mapping>
spring- context. xml
< servlet- name> spring- mvc< / servlet- name>
< ! -- 指定所有请求都通过DispatcherServlet来处理-- >
< url- pattern> / < / url- pattern>
< / servlet- mapping>
< / web- app>
< ? 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: 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/ tx
http: / / www. springframework. org/ schema/ tx/ spring- tx. xsd">
< context: property- placeholder
location= "classpath:database/database.properties" / >
< ! -- 配置c3p0连接池 -- >
< bean id= "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" >
< property name= "driverClass" value= "${jdbc.driverClass}" > < / property>
< property name= "jdbcUrl" value= "${jdbc.url}" > < / property>
< property name= "user" value= "${jdbc.username}" > < / property>
< property name= "password" value= "${jdbc.password}" > < / property>
< property name= "minPoolSize" value= "${jdbc.minPoolSize}" > < / property>
< property name= "maxPoolSize" value= "${jdbc.maxPoolSize}" > < / property>
< property name= "initialPoolSize" value= "${jdbc.initialPoolSize}" >
< / property>
< property name= "acquireIncrement" value= "${jdbc.acquireIncrement}" >
< / property>
< property name= "maxIdleTime" value= "${jdbc.maxIdleTime}" > < / property>
< property name= "maxStatements" value= "${jdbc.maxStatements}" > < / property>
< property name= "idleConnectionTestPeriod"
value= "${jdbc.idleConnectionTestPeriod}" > < / property>
< property name= "testConnectionOnCheckin" value= "false" > < / property>
< property name= "testConnectionOnCheckout" value= "true" > < / property>
< / bean>
< ! -- 配置事务管理器 -- >
< bean id= "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name= "dataSource" ref= "dataSource" > < / property>
< / bean>
< ! -- 使用注解来控制事务 -- >
< tx: annotation- driven transaction- manager= "transactionManager" / >
< ! -- 配置mybatis, 绑定c3p0-- >
< bean id= "sqlSessionFactory"
class = "org.mybatis.spring.SqlSessionFactoryBean" >
< property name= "dataSource" ref= "dataSource" > < / property>
spring- mvc. xml
< property name= "configLocation" value= "/WEB-INF/mybatis/mybatisconfig.xml" > < / property>
< property name= "mapperLocations" >
< list>
< value> classpath: mapper< / value>
< / list>
< / property>
< / bean>
< ! -- 在会话工厂中取出SqlSessionTemplate对象,用于执行项目的持久化操作 -- >
< bean class = "org.mybatis.spring.SqlSessionTemplate" >
< constructor- arg index= "0" ref= "sqlSessionFactory" / >
< / bean>
< ! -- 自动扫描 将Mapper接口生成代理注入到Spring -- >
< bean class = "org.mybatis.spring.mapper.MapperScannerConfigurer" >
< ! -- 给出需要扫描的接口,注意此处包名要换成自己项目中的Mapper接口所在的包名,如果有多个包,可以使用分号或者逗号隔开-- >
< property name= "basePackage" value= "com.yixiaojun.ssmdemo.dao" >
< / property>
< / bean>
< / beans>
< ? 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"
xsi: schemaLocation= "http: / / www. springframework. org/ schema/ beans
http: / / www. springframework. org/ schema/ beans/ spring- beans. xsd
http: / / www. springframework. org/ schema/ mvc
http: / / www. springframework. org/ schema/ mvc/ spring- mvc. 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">
< ! -- 开启Spring MVC注解驱动,它会自动注册DefaultAnnotationHandlerMapping与
AnnotationMethodHandlerAdapter两个bean, -- >
< ! -- 这两个bean是Spring MVC为@Controllers 分发请求所必须的,即解决了@Controller 注解使用的前提配置。-- >
< mvc: annotation- driven / >
< ! -- 开启跨域功能-- >
< ! --
< ? 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>
< setting name= "cacheEnabled" value= "true" / >
< setting name= "defaultStatementTimeout" value= "3000" / >
< ! -- 开启自动驼峰命名规则映射,如将数据库列名 A_COLUMN 映射成Java属性名aColumn-- >
< setting name= "mapUnderscoreToCamelCase" value= "true" / >
< ! -- 使用LOG4J2日志-- >
< setting name= "logImpl" value= "LOG4J2" / >
< ! -- 指定CGLIB代理 -- >
< setting name= "proxyFactory" value= "CGLIB" / >
< setting name= "lazyLoadingEnabled" value= "true" / >
< / settings>
< / configuration>
< ? xml version= "1.0" encoding= "UTF-8" ? >
< ! -- 日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL-- >
< ! -- Configuration后面的status, 这个用于设置log4j2自身内部的信息输出, 可以不设置, 当设置成
trace时, 你会看到log4j2内部各种详细输出-- >
< ! -- monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身, 设置间隔秒数-- >
< configuration status= "WARN" monitorInterval= "1800" >
< Properties>
< ! -- 日志默认存放的位置, 这里设置为项目根路径下, 也可指定绝对路径 -- >
< ! -- ${ web: rootDir} 是web项目根路径, java项目没有这个变量, 需要删掉, 否则会报异常 -- >
< property name= "basePath" > ${ web: rootDir} / log4j2Logs< / property>
< ! -- < property name= "basePath" > d: / qfxSpringMVCMybaitsDemoLogs< / property> -- >
< ! -- 控制台默认输出格式, "%-5level" : 日志级别, "%l" : 输出完整的错误位置, 是小写的L, 因为有行号显示, 所以影响日志输出的性能 -- >
< property name= "console_log_pattern" > % d{ yyyy- MM- dd HH: mm: ss. SSS} [ % - 5 level] % l - % m% n< / property>
< ! -- 日志文件默认输出格式, 不带行号输出( 行号显示会影响日志输出性能) ; % C: 大写, 类名; % M: 方法名; % m: 错误信息; % n: 换行 -- >
< property name= "log_pattern" > % d{ yyyy- MM- dd HH: mm: ss. SSS} [ % - 5 level] % C. %M - % m% n< / property>
< ! -- 日志默认切割的最小单位 -- >
< property name= "every_file_size" > 20 MB< / property>
< ! -- 日志默认输出级别 -- >
< property name= "output_log_level" > DEBUG< / property>
< ! -- 日志默认存放路径( 所有级别日志) -- >
< property name= "rolling_fileName" > ${ basePath} / all. log< / property>
< ! -- 日志默认压缩路径, 将超过指定文件大小的日志, 自动存入按"年月" 建立的文件夹下面并进行压缩, 作为存档 -- >
< property name= "rolling_filePattern" > ${ basePath} / % d{ yyyy- MM} / all- % d{ yyyy- MM- dd} - % i. log. gz< / property>
< ! -- 日志默认同类型日志, 同一文件夹下可以存放的数量, 不设置此属性则默认为7 个 -- >
< property name= "rolling_max" > 50 < / property>
< ! -- Info日志默认存放路径( Info级别日志) -- >
< property name= "info_fileName" > ${ basePath} / info. log< / property>
< ! -- Info日志默认压缩路径, 将超过指定文件大小的日志, 自动存入按"年月" 建立的文件夹下面并进行压缩, 作为存档 - >
< property name= "info_filePattern" > ${ basePath} / % d{ yyyy- MM} / info- % d{ yyyy- MM- dd} - % i. log. gz< / property>
< ! -- Info日志默认同一文件夹下可以存放的数量, 不设置此属性则默认为7 个 -- >
< property name= "info_max" > 10 < / property>
< ! -- Warn日志默认存放路径( Warn级别日志) -- >
< property name= "warn_fileName" > ${ basePath} / warn. log< / property>
< ! -- Warn日志默认压缩路径, 将超过指定文件大小的日志, 自动存入按"年月" 建立的文件夹下面并进行压缩, 作为存档 -- >
< property name= "warn_filePattern" > ${ basePath} / % d{ yyyy- MM} / warn- % d{ yyyy- MM- dd} - % i. log. gz< / property>
< ! -- Warn日志默认同一文件夹下可以存放的数量, 不设置此属性则默认为7 个 -- >
< property name= "warn_max" > 10 < / property>
< ! -- Error日志默认存放路径( Error级别日志) -- >
< property name= "error_fileName" > ${ basePath} / error. log< / property>
< ! -- Error日志默认压缩路径, 将超过指定文件大小的日志, 自动存入按"年月" 建立的文件夹下面并进行压缩, 作为存档 -- >
< property name= "error_filePattern" > ${ basePath} / % d{ yyyy- MM} / error- % d{ yyyy- MM- dd} - % i. log. gz< / property>
< ! -- Error日志默认同一文件夹下可以存放的数量, 不设置此属性则默认为7 个 -- >
< property name= "error_max" > 10 < / property>
< ! -- 控制台显示的日志最低级别 -- >
< property name= "console_print_level" > DEBUG< / property>
< / Properties>
< ! -- 定义appender -- >
< appenders>
< ! -- 用来定义输出到控制台的配置 -- >
< Console name= "Console" target= "SYSTEM_OUT" >
< ! -- 设置控制台只输出level及以上级别的信息( onMatch) , 其他的直接拒绝( onMismatch) -- >
< ThresholdFilter level= "${console_print_level}" onMatch= "ACCEPT" onMismatch= "DENY" / >
< ! -- 设置输出格式, 不设置默认为: % m% n -- >
< PatternLayout pattern= "${console_log_pattern}" / >
< / Console>
< ! -- 打印root中指定的level级别以上的日志到文件 -- >
< RollingFile name= "RollingFile" fileName= "${rolling_fileName}"
filePattern= "${rolling_filePattern}" >
< PatternLayout pattern= "${log_pattern}" / >
< SizeBasedTriggeringPolicy size= "${every_file_size}" / >
< ! -- 设置同类型日志, 同一文件夹下可以存放的数量, 如果不设置此属性则默认存放7 个文件-- >
< DefaultRolloverStrategy max= "${rolling_max}" / >
< ! -- 匹配INFO以及以上级别 -- >
< Filters>
< ThresholdFilter level= "INFO" onMatch= "ACCEPT" onMismatch= "DENY" / >
< / Filters>
< / RollingFile>
< ! -- 打印INFO级别的日志到文件 -- >
< RollingFile name= "InfoFile" fileName= "${info_fileName}"
filePattern= "${info_filePattern}" >
< PatternLayout pattern= "${log_pattern}" / >
< SizeBasedTriggeringPolicy size= "${every_file_size}" / >
< DefaultRolloverStrategy max= "${info_max}" / >
< ! -- 匹配INFO级别 -- >
< Filters>
< ThresholdFilter level= "WARN" onMatch= "DENY" onMismatch= "NEUTRAL" / >
< ThresholdFilter level= "INFO" onMatch= "ACCEPT" onMismatch= "DENY" / >
< / Filters>
< / RollingFile>
< ! -- 打印WARN级别的日志到文件 -- >
< RollingFile name= "WarnFile" fileName= "${warn_fileName}" filePattern= "${warn_filePattern}" >
< PatternLayout pattern= "${log_pattern}" / >
< SizeBasedTriggeringPolicy size= "${every_file_size}" / >
< DefaultRolloverStrategy max= "${warn_max}" / >
< ! -- 匹配WARN级别 -- >
< Filters>
< ThresholdFilter level= "ERROR" onMatch= "DENY"
onMismatch= "NEUTRAL" / >
< ThresholdFilter level= "WARN" onMatch= "ACCEPT"
onMismatch= "DENY" / >
< / Filters>
< / RollingFile>
< ! -- 打印ERROR级别的日志到文件 -- >
< RollingFile name= "ErrorFile" fileName= "${error_fileName}"
filePattern= "${error_filePattern}" >
< PatternLayout pattern= "${log_pattern}" / >
< SizeBasedTriggeringPolicy size= "${every_file_size}" / >
< DefaultRolloverStrategy max= "${error_max}" / >
< ! -- 匹配ERROR级别 -- >
< Filters>
< ThresholdFilter level= "FATAL" onMatch= "DENY" onMismatch= "NEUTRAL" / >
< ThresholdFilter level= "ERROR" onMatch= "ACCEPT" onMismatch= "DENY" / >
< / Filters>
< / RollingFile>
< / appenders>
< ! -- 然后定义logger, 只有定义了logger并引入的appender, appender才会生效-- >
< loggers>
< ! -- & lt; ! & ndash; 设置对打印sql语句的支持 & ndash; & gt; -- >
< logger name= "java.sql" level= "INFO" >
< appender- ref ref= "Console" / >
< / logger>
< logger name= "org.apache.ibatis" level= "INFO" >
< appender- ref ref= "Console" / >
< / logger>
< ! -- 建立一个默认的root的logger-- >
< root level= "${output_log_level}" >
< appender- ref ref= "RollingFile" / >
< appender- ref ref= "Console" / >
< appender- ref ref= "InfoFile" / >
< appender- ref ref= "WarnFile" / >
< appender- ref ref= "ErrorFile" / >
< / root>
< / loggers>
< / configuration>
至此,整个项目的基本配置已经配置好了,如果需要添加其他的功能,则可以根据需求来进行配置。
6.数据库搭建
在正式写我们的代码之前,我们还需要搭建一下数据库,下面给出我的SQL代码:
/*
Navicat MySQL Data Transfer
Source Server : 本机
Source Server Version : 50553
Source Host : localhost:3306
Source Database : sc
Target Server Type : MYSQL
Target Server Version : 50553
File Encoding : 65001
Date: 2019-07-8 09:43:22
*/
DROP TABLE IF EXISTS ` course` ;
CREATE TABLE ` course` (
` CId` varchar( 10) DEFAULT NULL,
` Cname` varchar( 10) DEFAULT NULL,
` TId` varchar( 10) DEFAULT NULL
) ENGINE= InnoDB DEFAULT CHARSET= utf8 ROW_FORMAT= DYNAMIC;
INSERT INTO ` course` VALUES ( '01' , '语文' , '02' ) ;
INSERT INTO ` course` VALUES ( '02' , '数学' , '01' ) ;
INSERT INTO ` course` VALUES ( '03' , '英语' , '03' ) ;
DROP TABLE IF EXISTS ` sc` ;
CREATE TABLE ` sc` (
` SId` varchar( 10) DEFAULT NULL,
` CId` varchar( 10) DEFAULT NULL,
` score` decimal( 18,1) DEFAULT NULL
) ENGINE= InnoDB DEFAULT CHARSET= utf8 ROW_FORMAT= DYNAMIC;
INSERT INTO ` sc` VALUES ( '01' , '01' , '80.0' ) ;
INSERT INTO ` sc` VALUES ( '01' , '02' , '90.0' ) ;
INSERT INTO ` sc` VALUES ( '01' , '03' , '99.0' ) ;
INSERT INTO ` sc` VALUES ( '02' , '01' , '70.0' ) ;
INSERT INTO ` sc` VALUES ( '02' , '02' , '60.0' ) ;
INSERT INTO ` sc` VALUES ( '02' , '03' , '80.0' ) ;
INSERT INTO ` sc` VALUES ( '03' , '01' , '80.0' ) ;
INSERT INTO ` sc` VALUES ( '03' , '02' , '80.0' ) ;
INSERT INTO ` sc` VALUES ( '03' , '03' , '80.0' ) ;
INSERT INTO ` sc` VALUES ( '04' , '01' , '50.0' ) ;
INSERT INTO ` sc` VALUES ( '04' , '02' , '30.0' ) ;
INSERT INTO ` sc` VALUES ( '04' , '03' , '20.0' ) ;
INSERT INTO ` sc` VALUES ( '05' , '01' , '76.0' ) ;
INSERT INTO ` sc` VALUES ( '05' , '02' , '87.0' ) ;
INSERT INTO ` sc` VALUES ( '06' , '01' , '31.0' ) ;
INSERT INTO ` sc` VALUES ( '06' , '03' , '34.0' ) ;
INSERT INTO ` sc` VALUES ( '07' , '02' , '89.0' ) ;
INSERT INTO ` sc` VALUES ( '07' , '03' , '98.0' ) ;
DROP TABLE IF EXISTS ` student` ;
CREATE TABLE ` student` (
` SId` int( 11) NOT NULL,
` Uid` int( 11) NOT NULL,
` Sname` varchar( 10) DEFAULT NULL,
` Sage` datetime DEFAULT NULL,
` Ssex` varchar( 10) DEFAULT NULL,
PRIMARY KEY ( ` SId` )
) ENGINE= InnoDB DEFAULT CHARSET= utf8 ROW_FORMAT= DYNAMIC;
INSERT INTO ` student` VALUES ( '1' , '1' , '赵雷' , '1990-01-01 00:00:00' , '男' ) ;
INSERT INTO ` student` VALUES ( '2' , '3' , '钱电' , '1990-12-21 00:00:00' , '男' ) ;
INSERT INTO ` student` VALUES ( '3' , '4' , '孙风' , '1990-12-20 00:00:00' , '男' ) ;
INSERT INTO ` student` VALUES ( '4' , '5' , '李云' , '1990-12-06 00:00:00' , '男' ) ;
INSERT INTO ` student` VALUES ( '5' , '8' , '周梅' , '1991-12-01 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '6' , '9' , '吴兰' , '1992-01-01 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '7' , '10' , '郑竹' , '1989-01-01 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '9' , '11' , '张三丰' , '2017-12-20 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '10' , '12' , '李武' , '2017-12-25 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '11' , '13' , '李洋' , '2012-06-06 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '12' , '14' , '赵六' , '2013-06-13 00:00:00' , '女' ) ;
INSERT INTO ` student` VALUES ( '13' , '15' , '孙七' , '2014-06-01 00:00:00' , '女' ) ;
DROP TABLE IF EXISTS ` teacher` ;
CREATE TABLE ` teacher` (
` TId` int( 10) NOT NULL AUTO_INCREMENT,
` Uid` int( 11) NOT NULL,
` Tname` varchar( 10) DEFAULT NULL,
` Tage` datetime DEFAULT NULL,
` TSex` varchar( 10) DEFAULT NULL,
PRIMARY KEY ( ` TId` )
) ENGINE= InnoDB AUTO_INCREMENT= 4 DEFAULT CHARSET= utf8 ROW_FORMAT= DYNAMIC;
INSERT INTO ` teacher` VALUES ( '1' , '2' , '张三' , '1970-03-01 00:00:00' , '男' ) ;
INSERT INTO ` teacher` VALUES ( '2' , '6' , '李四' , '1982-01-01 00:00:00' , '女' ) ;
INSERT INTO ` teacher` VALUES ( '3' , '7' , '王五' , '1993-01-01 00:00:00' , '男' ) ;
DROP TABLE IF EXISTS ` user` ;
CREATE TABLE ` user` (
` Uid` int( 11) NOT NULL AUTO_INCREMENT,
` account` varchar( 20) NOT NULL,
` password` varchar( 20) NOT NULL,
` role` int( 11) DEFAULT '1' COMMENT '1是学生,2是老师' ,
PRIMARY KEY ( ` Uid` ) ,
UNIQUE KEY ` account` ( ` account` )
) ENGINE= InnoDB AUTO_INCREMENT= 16 DEFAULT CHARSET= utf8;
INSERT INTO ` user` VALUES ( '1' , '123' , '123' , '1' ) ;
INSERT INTO ` user` VALUES ( '2' , '1234' , '1234' , '2' ) ;
INSERT INTO ` user` VALUES ( '3' , '12345' , '12345' , '1' ) ;
INSERT INTO ` user` VALUES ( '4' , '123456' , '12345' , '1' ) ;
INSERT INTO ` user` VALUES ( '5' , 'abc' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '6' , 'abc123' , '1234' , '2' ) ;
INSERT INTO ` user` VALUES ( '7' , 'admin' , 'admin' , '2' ) ;
INSERT INTO ` user` VALUES ( '8' , 'test' , 'test' , '1' ) ;
INSERT INTO ` user` VALUES ( '9' , 'admin123' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '10' , 'zhengzhu' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '11' , 'zhangsanfeng' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '12' , 'liwu' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '13' , 'liyang' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '14' , 'zhaoliu' , '1234' , '1' ) ;
INSERT INTO ` user` VALUES ( '15' , 'sunqi' , '1234' , '1' ) ;
7.写一个登录接口
首先,我们先来看一下项目代码结果,看一下编写一个登录接口需要哪些类。 接下来是具体的代码,首先是Model层的代码: ResponseContent.java
package com. yixiaojun. ssmdemo. bean;
import lombok. AllArgsConstructor;
import lombok. Data;
@AllArgsConstructor
@Data
public class ResponseContent {
private String code;
private String message;
private Object contents;
}
package com. yixiaojun. ssmdemo. bean;
import lombok. Data;
@Data
public class User {
int uId;
int role;
}
package com. yixiaojun. ssmdemo. bean;
import lombok. Data;
@Data
public class User {
int uId;
int role;
}
package com. yixiaojun. ssmdemo. utils;
import java. util. HashMap;
import java. util. Map;
public class Constant {
public final static String SUCCESS_CODE = "CO1" ;
public final static String ERROR_CODE = "E01" ;
JsonResolver. java
public final static String SUCCESS_MESSAGE = "调用成功" ;
public final static Map< String, String> SEESION_MAP = new HashMap < > ( ) ;
}
package com. yixiaojun. ssmdemo. utils;
import com. google. gson. *;
import com. google. gson. reflect. TypeToken;
import com. yixiaojun. ssmdemo. bean. ResponseContent;
import lombok. Cleanup;
import lombok. SneakyThrows;
import javax. servlet. http. HttpServletRequest;
import java. io. ByteArrayOutputStream;
import java. io. IOException;
import java. lang. reflect. Type;
import java. util. HashMap;
import java. util. Map;
import java. util. Set;
public class JsonResolver {
private final static int BUFFER_SIZE = 4096 ;
private Gson gson;
private static JsonResolver jsonResolver;
private JsonResolver ( ) {
HashMap< String, Object>
gson = new GsonBuilder ( ) . registerTypeAdapter ( new
TypeToken < HashMap< String, Object> > ( ) { } . getType ( ) , new
JsonDeserializer < HashMap< String, Object> > ( ) {
@Override
public HashMap< String, Object> deserialize ( JsonElement jsonElement,
Type type, JsonDeserializationContext jsonDeserializationContext) throws
JsonParseException {
HashMap< String, Object> hashMap = new HashMap < > ( 16 ) ;
JsonObject jsonObject = jsonElement. getAsJsonObject ( ) ;
Set< Map. Entry< String, JsonElement> > entrySet =
jsonObject. entrySet ( ) ;
for ( Map. Entry< String, JsonElement> entry : entrySet) {
if ( entry. getValue ( ) instanceof JsonArray ) {
hashMap. put ( entry. getKey ( ) , entry. getValue ( ) ) ;
} else {
hashMap. put ( entry. getKey ( ) , entry. getValue ( ) . toString ( ) . replace ( "\"" , "" ) ) ;
}
}
return hashMap;
}
} ) . create ( ) ;
}
public static JsonResolver getInstance ( ) {
if ( jsonResolver == null) {
jsonResolver = new JsonResolver ( ) ;
}
return jsonResolver;
}
@SneakyThrows
public HashMap< String, Object> request2HashMap ( HttpServletRequest request) {
HashMap< String, Object> map = new HashMap < > ( 16 ) ;
String requestParm = null;
requestParm = new String ( inputStreamToByte ( request) , "UTF-8" ) ;
requestParm = java. net. URLDecoder. decode ( requestParm, "UTF-8" ) ;
map = gson. fromJson ( requestParm, new TypeToken < HashMap< String, Object> > ( )
{ } . getType ( ) ) ;
return map;
}
@SneakyThrows
private byte [ ] inputStreamToByte ( HttpServletRequest request) {
@Cleanup ByteArrayOutputStream outStream = new ByteArrayOutputStream ( ) ;
byte [ ] data = new byte [ BUFFER_SIZE] ;
int count = - 1 ;
while ( ( count = request. getInputStream ( ) . read ( data, 0 , BUFFER_SIZE) ) !=
- 1 ) {
outStream. write ( data, 0 , count) ;
}
return outStream. toByteArray ( ) ;
}
@SneakyThrows
public String jsonAssembly ( String code, String message, Object content) {
ResponseContent responseContent = new
ResponseContent ( code, message, content) ;
LogInterceptor. java
String jsonStr = null;
jsonStr = gson. toJson ( responseContent) ;
return jsonStr;
}
}
package com. yixiaojun. ssmdemo. utils;
import lombok. extern. slf4j. Slf4j;
import org. aspectj. lang. ProceedingJoinPoint;
import org. aspectj. lang. annotation. Around;
import org. aspectj. lang. annotation. Aspect;
import org. springframework. stereotype. Component;
import javax. servlet. http. HttpServletRequest;
import javax. servlet. http. HttpServletResponse;
import java. util. HashMap;
@Slf4j
@Aspect
@Component
public class LogInterceptor {
@Around ( "execution(* com.yixiaojun.ssmdemo.controller..*.*(..))" )
public void process ( ProceedingJoinPoint joinPoint) throws Throwable {
String apiName = joinPoint. getTarget ( ) . getClass ( ) . getName ( ) + "."
+ joinPoint. getSignature ( ) . getName ( ) ;
HttpServletRequest request = ( HttpServletRequest) joinPoint. getArgs ( ) [ 0 ] ;
HashMap< String, Object> map =
JsonResolver. getInstance ( ) . request2HashMap ( request) ;
HttpServletResponse response = ( HttpServletResponse) joinPoint. getArgs ( )
[ 1 ] ;
response. setContentType ( "application/json;charset=UTF-8" ) ;
log. info ( "------接口-----" + apiName + "()-------start-----" ) ;
String loginFunName =
"com.yixiaojun.ssmdemo.controller.UserController.login" ;
String changePasswordFunName =
"com.yixiaojun.ssmdemo.controller.UserController.changePassword" ;
String registerFunName =
"com.yixiaojun.ssmdemo.controller.UserController.register" ;
回
if ( ! ( loginFunName. equals ( apiName) ||
changePasswordFunName. equals ( apiName) || registerFunName. equals ( apiName) ) ) {
String sessionIdKey = "sessionId" ;
if
( com. yixiaojun. ssmdemo. utils. Constant. SEESION_MAP. get ( map. get ( sessionIdKey) . toSt
ring ( ) ) == null) {
response. getWriter ( ) . print ( JsonResolver. getInstance ( ) . jsonAssembly ( com. yixiaoju
n. ssmdemo. utils. Constant. ERROR_CODE, "调用失败" , null) ) ;
log. info ( "------接口-----" + apiName + "()-------end-----" ) ;
return ;
}
}
request. setAttribute ( "paramMap" , map) ;
Object[ ] args = new Object [ ] { request, response} ;
joinPoint. proceed ( args) ;
log. info ( "------接口-----" + apiName + "()-------end-----" ) ;
}
}
package com. yixiaojun. ssmdemo. dao;
import com. yixiaojun. ssmdemo. bean. User;
import org. apache. ibatis. annotations. Param;
import org. springframework. stereotype. Repository;
@Repository
public interface UserDao {
User login ( @Param ( "account" ) String account, @Param ( "password" ) String
password) ;
}
接着是Service层的代码: UserService.java
package com. yixiaojun. ssmdemo. service;
import com. yixiaojun. ssmdemo. bean. User;
public interface UserService {
User login ( String account, String password) ;
}
package com. yixiaojun. ssmdemo. service;
import com. yixiaojun. ssmdemo. bean. User;
import com. yixiaojun. ssmdemo. dao. UserDao;
import org. springframework. beans. factory. annotation. Autowired;
import org. springframework. stereotype. Service;
@Service ( value = "UserServiceImpl" )
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
public User login ( String account, String password) {
return userDao. login ( account, password) ;
}
}
最后是控制层的代码: UserController.java
package com. yixiaojun. ssmdemo. controller;
import com. yixiaojun. ssmdemo. bean. User;
import com. yixiaojun. ssmdemo. service. UserService;
import com. yixiaojun. ssmdemo. utils. Constant;
import com. yixiaojun. ssmdemo. utils. JsonResolver;
import org. springframework. stereotype. Controller;
import org. springframework. web. bind. annotation. RequestMapping;
import org. springframework. web. bind. annotation. RequestMethod;
import javax. annotation. Resource;
import javax. servlet. http. HttpServletRequest;
import javax. servlet. http. HttpServletResponse;
import java. io. IOException;
import java. util. HashMap;
@Controller
@RequestMapping ( "/user" )
public class UserController {
@Resource ( name = "UserServiceImpl" )
UserService userService;
@RequestMapping ( value = "/login" , method = RequestMethod. POST)
public void login ( HttpServletRequest request, HttpServletResponse response)
throws IOException {
@SuppressWarnings ( "unchecked" )
HashMap< String, Object> map = ( HashMap< String, Object> ) request. getAttribute ( "paramMap" ) ;
Useruser= userService. login ( map. get ( "account" ) . toString ( ) , map. get ( "password" ) . toString ( ) ) ;
response. getWriter ( ) . print ( JsonResolver. getInstance ( ) . jsonAssembly ( Constant. SUCCESS_CODE, Constant. SUCCESS_MESSAGE, user) ) ;
}
}
至此,我们的代码已经全部写好了,但是在将我们的代码跑起来之前,我们还需要配置下Tomcat: 1.首先,在工具栏找到下图中的Edit Configurations,点击进入配置窗口。 2.接下来在配置窗口添加Tomcat服务器。 到这里,我们就配置好了Tomcat服务器了,可以愉快地点击工具栏的运行按钮来运行项目了. 考虑到有的同学不知道war和war exploded的区别,我在这里简单地解释一下: war模式:将WEB工程以包的形式上传到服务器 war exploded模式:将WEB工程以当前文件夹的位置关系上传到服务器
理
解
\color{blue}{理解}
理 解 1)war模式这种可以称之为是发布模式,看名字也知道,这是先打成war包,再发布 2)war exploded模式是直接把文件夹、jsp页面 、classes等等移到Tomcat 部署文件夹(target目录)里面,进行加载部署。因此这种方式支持热部署,一般在开发的时候也是用这种方式。 3)在平时开发的时候,使用热部署的话,应该对Tomcat进行相应的设置,这样的话修改的jsp界面才可以及时的显示出来。
对
比
\color{blue}{对比}
对 比 通过war模式获取项目的相对路径是Tomcat的安装目录所在位置,看出通过war模式是最终打包部署到Tomcat的安装目录的所在位置。 通过war exploded模式获取项目的相对路径是项目target目录的位置,看出通过war模式是最终打包部署到项目target目录的位置。
结
论
\color{blue}{结论}
结 论 两种方式得部署方式是不一样的,因此在获取项目的相对路径的时候得到的结果是不一样的。
8.使用Postman测试接口
将以上工作都做好了之后,我们就可以在Postman测试一下我们写的接口是否可以正常使用了,我们新建一个测试请求,按照下图填好相关的接口URL和参数和请求方式。 然后我们点击一下右上角的Send按钮,就可以在下方看见接口返回的数据了。