ssm框架搭建

                                             SSM框架搭建

1.新建一个Maven项目

打开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>

3.新建类目录和资源目录

在src下面的main文件夹上右击,New->Directory,新建一个Java目录和一个resources目录

<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文件目录下右键,然后输入两个包的全路径:com.yixiaojun.ssdmdemo.controller,com.yixiaojun.ssdmdemo.service,这样就可以出现两个子包在同一级下的效果了,然后就可以右键父包,输入其他子包的名字,从而创建出上图中的包结构了。

5.配置项目

当上面的任务都完成了之后,就可以对项目进行配置了,在进行配置之前,我们需要按照下图的文件结构创建几个文件夹和配置文件。

配置文件的内容如下:

database.properties

jdbc.driverClass=com.mysql.cj.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/sc?

serverTimezone=GMT%2B8&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后面的值需要换成自己的数据库地址,jdbc.username后面的值需要换成自己的数据库用户名,jdbc.password后面的值需要换成自己的用户密码。

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>/*</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>


spring-context.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: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/*.xml</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>


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"

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 />

<!--开启跨域功能-->

<!--/**的意思是所有文件夹及里面的子文件夹-->

<!--/*是所有文件夹,不含子文件夹-->

<!--/是web项目的根目录-->

<mvc:cors>

<mvc:mapping path="/**"/>

</mvc:cors>

<!-- 让Spring扫描这个包下所有的类,让标注Spring注解的类生效,此处的包名应改为自己项目的包名 -->

<context:component-scan base-package="com.yixiaojun.ssmdemo" />

<!--为Spring容器中那些配置@Aspect切面的bean创建代理,织入切面,根据运行类选择 JDK 或

CGLIB 代理-->

<aop:aspectj-autoproxy/>

</beans>


mybatis-config.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>

<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>


log4j2.xml

<?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}[%-5level] %l - %m%n</property>

<!-- 日志文件默认输出格式,不带行号输出(行号显示会影响日志输出性能);%C:大写,类名;%M:方法名;%m:错误信息;%n:换行 -->

<property name="log_pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]%C.%M - %m%n</property>

<!-- 日志默认切割的最小单位 -->

<property name="every_file_size">20MB</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

*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------

-- Table structure for course

-- ----------------------------

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;

-- ----------------------------

-- Records of course

-- ----------------------------

INSERT INTO `course` VALUES ('01', '语文', '02');

INSERT INTO `course` VALUES ('02', '数学', '01');

INSERT INTO `course` VALUES ('03', '英语', '03');

-- ----------------------------

-- Table structure for sc

-- ----------------------------

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;

-- ----------------------------

-- Records of sc

-- ----------------------------

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');

-- ----------------------------

-- Table structure for student

-- ----------------------------

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;

-- ----------------------------

-- Records of student

-- ----------------------------

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', '女');

-- ----------------------------

-- Table structure for teacher

-- ----------------------------

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;

-- ----------------------------

-- Records of teacher

-- ----------------------------

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', '男');

-- ----------------------------

-- Table structure for user

-- ----------------------------

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;

-- ----------------------------

-- Records of user

-- ----------------------------

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;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@AllArgsConstructor

@Data

public class ResponseContent {

private String code;

User.java

Student.java

接下来是工具类:

Constant.java

private String message;

private Object contents;

}


User.java

package com.yixiaojun.ssmdemo.bean;

import lombok.Data;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@Data

public class User {

int uId;

int role;

}


Student.java

package com.yixiaojun.ssmdemo.bean;

import lombok.Data;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@Data

public class User {

int uId;

int role;

}

接下来是工具类:

Constant.java

package com.yixiaojun.ssmdemo.utils;

import java.util.HashMap;

import java.util.Map;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

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<>();

}


JsonResolver.java

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;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

public class JsonResolver {

private final static int BUFFER_SIZE = 4096;

private Gson gson;

private static JsonResolver jsonResolver;

private JsonResolver(){

//根据自己需要将Json解析成的类型来创建一个Gson对象,此处的参数类型为

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();

}

/**

* 使用单例模式生成一个对象JsonResolver对象

* @return 返回一个JsonResolver对象

*/

public static JsonResolver getInstance(){

if (jsonResolver == null){

jsonResolver = new JsonResolver();

}

return jsonResolver;

}

/**

* 将request对象里面的参数通过Gson转成HashMap<String, Object>

* @param request

* @return 存放解析之后的参数的map

*/

@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;

}

/**

* 将获取到的输入流转成字节数组

* @param request

* @return

* @throws IOException

*/

@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();

}

/**

* 将要返回给前端数据转换成Json格式

* @param code 标识码,标识接口调用成功或失败

* @param message 提示信息

* @param content 真正要获取的内容

* @return

*/

@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;

}

}


LogInterceptor.java

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;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@Slf4j

@Aspect

@Component

public class LogInterceptor {

/**

* 拦截所有的controller包下面的接口(方法),使用了AOP的方法,在调用controller包下的

方法时都会先调用这个方法,经过处理之后才会转发到真正的方法

* @param joinPoint

* @throws Throwable

*/

@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];

//将前端传过来的数据解析成Map

HashMap<String,Object> map =

JsonResolver.getInstance().request2HashMap(request);

HttpServletResponse response = (HttpServletResponse)joinPoint.getArgs()

[1];

//将字符编码改成UTF-8,解决部分浏览器在控制台显示乱码问题

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";

//如果不是调用登录、修改密码、注册三个接口,就进行一次sessionId验证,验证不通过直接返

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;

}

}

/**

* Spring中request.getInputStream() 和request.getReader()只能被获取一次,

* 而@RequestBody注解参数的底层实现也是通过流来获取请求参数的,

* 所以需要将解析完的参数用一个键值对存起来,以便在控制层直接读取

*/

request.setAttribute("paramMap",map);

Object[] args = new Object[]{request, response};

joinPoint.proceed(args);

log.info("------接口-----"+ apiName + "()-------end-----");

}

}

接着是Dao层的代码:


UserDao.java

package com.yixiaojun.ssmdemo.dao;

import com.yixiaojun.ssmdemo.bean.User;

import org.apache.ibatis.annotations.Param;

import org.springframework.stereotype.Repository;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@Repository

public interface UserDao {

/**

* 根据帐号密码查询用户

接着是Service层的代码:

UserService.java

UserServiceImpl.java

* @Author:yixiaojun

* @param account 帐号

* @param password 密码

* @return 根据帐号密码查询到的用户信息或者为空

*/

User login(@Param("account") String account, @Param("password") String

password);

}

接着是Service层的代码:


UserService.java

package com.yixiaojun.ssmdemo.service;

import com.yixiaojun.ssmdemo.bean.User;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

public interface UserService {

/**

* 根据帐号密码查询用户

* @Author:yixiaojun

* @param account 帐号

* @param password 密码

* @return 根据帐号密码查询到的用户信息

*/

User login(String account, String password);

}


UserServiceImpl.java

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;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@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;

/**

* @Author:yixiaojun

* @Date:2019/7/8

* @Description:

*/

@Controller

@RequestMapping("/user")

public class UserController {

@Resource(name = "UserServiceImpl")

UserService userService;

/**

* 登录接口,用户登录时调用

* @Author:yixiaojun

* @param request 前端传来的参数,参数为Json格式,示例为:

{"account":"1234","password":"1234"},分别代表账号和密码

* @param response

* @throws IOException

*/

@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");

User user =

userService.login(map.get("account").toString(),map.get("password").toString());

response.getWriter().print(JsonResolver.getInstance().jsonAssembly(Constant.SUC

CESS_CODE,Constant.SUCCESS_MESSAGE,user));

}

}


至此,我们的代码已经全部写好了,但是在将我们的代码跑起来之前,我们还需要配置一下Tomcat:

1.首先,在工具栏找到下图中的Edit Configurations,点击进入配置窗口。

2.接下来在配置窗口添加Tomcat服务器。

到这里,我们就配置好了Tomcat服务器了,可以愉快地点击工具栏的运行按钮来运行项目了。

考虑到有的同学不知道war和war exploded的区别,我在这里简单地解释一下:

war模式:将WEB工程以包的形式上传到服务器 ;

war exploded模式:将WEB工程以当前文件夹的位置关系上传到服务器

理解:

(1)war模式这种可以称之为是发布模式,看名字也知道,这是先打成war包,再发布;

(2)war exploded模式是直接把文件夹、jsp页面 、classes等等移到Tomcat 部署文件夹(target目

录)里面,进行加载部署。因此这种方式支持热部署,一般在开发的时候也是用这种方式。

(3)在平时开发的时候,使用热部署的话,应该对Tomcat进行相应的设置,这样的话修改的jsp界面

什么的东西才可以及时的显示出来。

对比:

通过war模式获取项目的相对路径是Tomcat的安装目录所在位置,看出通过war模式是最终打包部

署到Tomcat的安装目录的所在位置。

通过war exploded模式获取项目的相对路径是项目target目录的位置,看出通过war模式是最终打

包部署到项目target目录的位置。

结论:

两种方式得部署方式是不一样的,因此在获取项目的相对路径的时候得到的结果是不一样的。

8.使用Postman测试接口

将以上工作都做好了之后,我们就可以在Postman测试一下我们写的接口是否可以正常使用了,我们新建一个测试请求,按照下图填好相关的接口URL和参数和请求方式。

然后我们点击一下右上角的Send按钮,就可以在下方看见接口返回的数据了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容