1.Mybatis
1.mybatis的作用
mybatis的作用就是为了将MVC中dao成的实现类替代,使用xml文件的方法完成与数据库的交互.
2.mybatis的配置
我的jdbc配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/xa_2106?characterEncoding=utf-8
username=root
password=123456
2.1mybatis-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">
<configration>
<!--引入properties文件 -->
<properties resource="jdbc配置文件"></properties>
<!-- 设置-->
<settings>
<!-- 一级缓存默认开启,开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--别名配置-->
<typeAliase>
<!--别名配置,包名下的所有类给别名,dao包,别名是类名首字母小写-->
<package name="">
</typeAliase>
<!-- plugins-->
<plugins>
<!-- pageHelp 分页插件-->
<plugin> interceptor="com.github.pagehelper.PageInterceptor">
</plugin>
</plugins>
<!--数据源 -->
<environments default="dev">
<!--可以配置多个数据源 -->
<environment id="dev">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 加载SqlMapper.xml文件
mapper.xml就是与数据库交互的文件
<mapper resource="sqlMapper.xml的位置"></mapper>
-->
<mappers>
<mapper resource="mapper/TeacherMapper.xml"></mapper>
<mapper resource="mapper/OrderMapper.xml"></mapper>
</mappers>
</configration>
2.2sqlMapper的配置
传参方式:
1.传入一个对象 通过#{属性名}
2.传入一个基本类型 如果只有一个,则#{}中可以任意定义,但是当传入多个参数时,需要通过下标 从0开始,或者param1... 来进行获取
3.传入一个map集合,#{}中填写的map中的key值
4.注解方式 通过接口中的@Param("key") 来进行传参
<?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">
<!--namespace 接口的全限定类名 一个xml跟一个接口进行绑定 -->
<mapper namespace="com.qf.dao.TeacherMapper">
<!--
resultType 返回的结果集的类型
parameterType 传入的参数类型
-->
<select id="findAll" resultType="com.qf.pojo.Teacher">
SELECT id,teacher_name as teacherName,age,sex FROM `tb_teacher`
</select>
<insert id="insertTeacher" parameterType="com.qf.pojo.Teacher">
insert into tb_teacher (id,teacher_name,age,sex) values (null,#{teacherName},#{age},#{sex})
</insert>
<!-- 传入参数
#{} ==>获取传入的参数
1.传入一个对象 通过#{属性名}
2.传入一个基本类型 如果只有一个,则#{}中可以任意定义,但是当传入多个参数时,需要通过下标 从0开始,或者param1... 来进行获取
3.传入一个map集合,#{}中填写的map中的key值
4.注解方式 通过接口中的@Param("key") 来进行传参
-->
<select id="findById" resultType="com.qf.pojo.Teacher">
select * from tb_teacher where id = #{id} and age=#{age}
</select>
</mapper>
2.3sqlMapper查询映射
<resultMap id="映射名" type="实体类的类型">
<!--主键进行关联映射-->
<id property="实体属性" column="数据库列名"></id>
<!-- 普通列结果集映射-->
<result property="实体属性" column="数据库列名"></result>
<!-- <constructor>-->
<!--主键-->
<!--<idArg column="id" javaType="int" ></idArg>-->
<!--<arg column="user_id" javaType="int" />-->
<!--<arg column="order_price" javaType="DOUBLE" />-->
<!--<arg column="update_time" javaType="DATE" />-->
<!--<arg column="create_time" javaType="DATE" />-->
<!-- </constructor>-->
</resultMap>
<select id="dao中的方法名" resultMap="映射名">
SELECT * FROM `tb_order`;
</select>
<?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="com.qf.dao.OrderDao">
<!-- 进行结果集映射-->
<resultMap id="baseResult" type="tbOrder">
<!-- 主键进行关联映射-->
<id property="id" column="id"></id>
<!-- 普通列结果集映射-->
<!-- <result property="orderPrice" column="order_price"></result>-->
<!-- <result property="userId" column="user_id"></result>-->
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
<!-- <constructor>-->
<!-- <!– 主键–>-->
<!-- <idArg column="id" javaType="int" ></idArg>-->
<!-- <arg column="user_id" javaType="int" />-->
<!-- <arg column="order_price" javaType="DOUBLE" />-->
<!-- <arg column="update_time" javaType="DATE" />-->
<!-- <arg column="create_time" javaType="DATE" />-->
<!-- </constructor>-->
</resultMap>
<resultMap id="orderUserResult" type="tbOrder">
<!-- 主键进行关联映射 -->
<id property="id" column="id"></id>
<!-- 普通列结果集映射-->
<result property="orderPrice" column="order_price"></result>
<result property="userId" column="user_id"></result>
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
<!-- 一对一的关系映射
property: 该类中的属性名
javaType: 全限定类名
-->
<association property="tbUser" javaType="tbUser">
<id column="id" property="id"></id>
<result column="user_name" property="userName"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
</association>
</resultMap>
<resultMap id="orderDetailResult" type="tbOrder">
<!-- 主键进行关联映射 -->
<id property="id" column="id"></id>
<!-- 普通列结果集映射-->
<result property="orderPrice" column="order_price"></result>
<result property="userId" column="user_id"></result>
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
<association property="tbUser" javaType="tbUser">
<id column="id" property="id"></id>
<result column="user_name" property="userName"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
</association>
<!-- 一对多的关联关系-->
<collection property="tbOrderDetailList" ofType="tbOrderDetail">
<id property="orderDetailId" column="order_detail_id"></id>
<result property="orderDetailPrice" column="order_detail_price"></result>
<result property="shopId" column="shop_id"></result>
<result property="createTime" column="create_time"></result>
</collection>
</resultMap>
<resultMap id="orderDetailShopsResult" type="tbOrder">
<!-- 主键进行关联映射 -->
<id property="id" column="id"></id>
<!-- 普通列结果集映射-->
<result property="orderPrice" column="order_price"></result>
<result property="userId" column="user_id"></result>
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
<association property="tbUser" javaType="tbUser">
<id column="id" property="id"></id>
<result column="user_name" property="userName"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
</association>
<!-- 一对多的关联关系-->
<collection property="tbOrderDetailList" ofType="tbOrderDetail">
<id property="orderDetailId" column="order_detail_id"></id>
<result property="orderDetailPrice" column="order_detail_price"></result>
<result property="shopId" column="shop_id"></result>
<result property="createTime" column="create_time"></result>
<!-- 一对一的关联关系-->
<association property="tbShop" javaType="tbShop">
<id property="shopId" column="shop_id"></id>
<result property="shopName" column="shop_name"></result>
<result property="shopDes" column="shop_des"></result>
<result property="shopPrice" column="shop_price"></result>
</association>
</collection>
</resultMap>
<select id="findAll" resultMap="baseResult">
SELECT * FROM `tb_order`;
</select>
<select id="findOrderUser" resultMap="orderUserResult">
select * from tb_order od,tb_user tu where od.user_id=tu.id ;
</select>
<select id="findOrderAndOrderDetails" resultMap="orderDetailResult">
SELECT * FROM tb_order od,`tb_order_detail` tod,tb_user tu where od.user_id=tu.id and od.id=tod.order_id;
</select>
<select id="findOrderAndOrderDetailAnShop" resultMap="orderDetailShopsResult">
SELECT * FROM tb_order od,`tb_order_detail` tod,tb_user tu,tb_shop ts where od.user_id=tu.id and od.id=tod.order_id and tod.shop_id=ts.shop_id;
</select>
</mapper>
2.4log4j日志配置
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
# 全局日志配置
#日志等级:1.ERROR 2.INFO 3.TRACE 4.DEBUGGER 线上部署时,使用的时ERROR
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置 根据需要修改
log4j.logger.com.qf.dao=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
2.5动态sql语句
xml当中的符号
< < 小于号
> > 大于号
& & 和
' ’ 单引号
" " 双引号
1.<sql id=""> 避免重复写select到的结果列 用<include refid="sql的id">
2.<if test="条件"> 满足条件才执行
3.<choose>
<when test="条件">
<otherwise> 都不满足的时候执行
</choose>
4.<trim prefix:前缀 prefixoverride:去掉前缀中的第一个信息
suffix:后缀 suffixoverride:去掉后缀后的第一个信息>
5.<set>标签,在update的时候,替换<trim>使用,好用
6.<foreach collection="集合数据" item="每一个值" open="开始符号" spearator="每个数据由什么隔开" close="结束符号"> 用于批量增删,牛逼
<mapper namespace="com.qf.dao.ShopDao">
<resultMap id="baseResult" type="tbShop">
<id column="shop_id" property="shopId"></id>
<result column="shop_name" property="shopName"></result>
<result column="shop_price" property="shopPrice"></result>
<result column="shop_des" property="shopDes"></result>
</resultMap>
<sql id="baseSql">
shop_id,shop_name,shop_price,shop_des
</sql>
<select id="findAll" resultMap="baseResult">
select <include refid="baseSql"></include> from tb_shop;
</select>
<select id="findByShopNameAndPrice" resultMap="baseResult">
select <include refid="baseSql"></include> from tb_shop where 1=1
<if test="shopName!=null and shopName!=''">
and shop_name=#{shopName}
</if>
<if test="price!=null">
and shop_price < #{price}
</if>
</select>
<select id="findByShopNameAndPriceChoose" resultMap="baseResult">
select <include refid="baseSql"></include> from tb_shop
<where>
<choose>
<when test="shopName!=null and shopName!=''">
and shop_name=#{shopName}
</when>
<when test="price!=null">
and shop_price < #{price}
</when>
<otherwise>
and shop_id = 1
</otherwise>
</choose>
</where>
</select>
<update id="updateById" parameterType="tbShop">
update tb_shop
<!-- 可以用<set>标签替换<trim>,比<trim好用> -->
<trim prefix="set" suffixOverrides=",">
<if test="shopName!=null and shopName!=''">
shop_name=#{shopName},
</if>
<if test="shopPrice!=null">
shop_price=#{shopPrice},
</if>
<if test="shopDes!=null and shopDes!=''">
shop_des=#{shopDes},
</if>
</trim>
<where>
shop_id = #{shopId}
</where>
</update>
<delete id="deleteByIds" >
delete from tb_shop
<where>
shop_id in
</where>
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
<insert id="insertAll">
insert into tb_shop (shop_id,shop_name,shop_des,shop_price) VALUES
<foreach collection="list" item="item" separator=",">
(null,#{item.shopName},#{item.shopDes},#{item.shopPrice})
</foreach>
</insert>
</mapper>
2.spring
1.spring的作用
为了在项目中降低数据的耦合度,也就是减少new对象的过程,我们将new对象的权限从程序员手中交给spring,**spring默认是单例模式创建对象,也就是创建出的对象地址值一样!**减少内存的消耗.
另外,可以黏合mybatis框架一起使用
ssm分别对应mvc三层架构
2.spring的配置
2.1Ioc(Inversion of controller)控制翻转
将new对象的权利从程序员手中交到spring工厂,就是控制翻转
<bean id="类名/接口名" class="全限定类名/别名">
2.2Di(Dependency injection)依赖注入
spring在新建对象时为其属性赋值,称为依赖注入
三种注入方式<bean>中:
1.通过set/get方法:<property name="实体属性" value="值">
2.通过构造器:<constructor-arg name="实体属性" value="值">
3.p标签,p:属性=值
实体属性是非基本类型的情况:
1.是数组时:
<property name="实体属性">
<array>
<value>踢足球</value>
<value>踢篮球</value>
<value>踢羽毛球</value>
</array>
</property>
2.是set集合时:
<property name="实体属性">
<set>
<value>121</value>
<value>123</value>
<value>123</value>
<value>124</value>
</set>
</property>
3.是list集合时:
<property name="实体属性">
<list>
<value>颤三</value>
<value>王五</value>
<value>赵六</value>
</list>
</property>
4.是map集合时:
<property name="实体属性">
<map>
<entry key="bj" value="北京"></entry>
<entry key="xa" value="西安"></entry>
<entry key="xg" value="香港"></entry>
<entry key="tl" value="铁岭"></entry>
</map>
</property>
5.是peoperties时:
<property name="files">
<props>
<prop key="one">one</prop>
<prop key="two">two</prop>
</props>
</property>
2.3spring-context.xml配置示例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!--
什么是IOC
控制反转
程序员手中对对象实例化,初始化的控制权。转到了spring框架中
DI
依赖注入
<bean id="userService" class="com.qf.service.impl.UserServiceImpl" ></bean>
-->
<!-- 实例化/初始化对象
初始化对象时 三种赋值方式
1.get/set方式赋值,当前对象中必须有属性的get/set方法 <property name="属性名" value="值">
2.构造器赋值。<constructor-arg name="属性名" value="值">
3.p标签 p:属性值=value
-->
<bean id="tbUser" class="com.qf.pojo.TbUser">
<property name="id" value="1"></property>
<property name="name" value="张宁"></property>
<property name="age" value="2"></property>
<property name="tbUserInfo" ref="tbUserInfo2"></property>
</bean>
<!-- <bean id="tbUser" class="com.qf.pojo.TbUser">-->
<!-- <constructor-arg name="age" value="1"></constructor-arg>-->
<!-- <constructor-arg name="id" value="1"></constructor-arg>-->
<!-- <constructor-arg name="name" value="扎根"></constructor-arg>-->
<!-- <constructor-arg name="tbUserInfo" ref="tbUserInfo2"></constructor-arg>-->
<!-- </bean>-->
<!--
-->
<!-- <bean id="tbUser" class="com.qf.pojo.TbUser" p:name="张三" p:age="11" p:id="12" p:tbUserInfo-ref="tbUserInfo2"></bean>-->
<bean id="tbUserInfo2" class="com.qf.pojo.TbUserInfo" p:addr="南窑头国际城" p:idCard="1111" p:phone="134" p:userId="1"></bean>
<!-- 实体类对象的基本数据类型的初始化-->
<bean id="user" class="com.qf.pojo.User">
<property name="password" value="ceshi"></property>
<property name="sex" value="1"></property>
<property name="age" value="2"></property>
<property name="bornDate" value="2021/09/16"></property>
<property name="hobbys">
<array>
<value>踢足球</value>
<value>踢篮球</value>
<value>踢羽毛球</value>
</array>
</property>
<property name="phones">
<set>
<value>121</value>
<value>123</value>
<value>123</value>
<value>124</value>
</set>
</property>
<property name="names">
<list>
<value>颤三</value>
<value>王五</value>
<value>赵六</value>
</list>
</property>
<property name="countries">
<map>
<entry key="bj" value="北京"></entry>
<entry key="xa" value="西安"></entry>
<entry key="xg" value="香港"></entry>
<entry key="tl" value="铁岭"></entry>
</map>
</property>
<property name="files">
<props>
<prop key="one">one</prop>
<prop key="two">two</prop>
</props>
</property>
</bean>
<!-- Di
当前依赖的对象必须全部交由spring来管理,如果spring不管理该对象,则无法进行注入操作,会报出NullpointException
-->
<bean id="userService" class="com.qf.service.impl.UserServiceImpl" >
<property name="userDao" ref="userDao"></property>
</bean>
<!--
init-method 初始化对象时执行的方法
destroy-method spring容器关闭时执行的方法
scope 标识当前对象声明时是单例还是多例,默认是单例
单例下:当前 IOC容器创建时就已经创建完成。
多例下:什么时候使用,才创建
lazy-init: 延迟创建对象,当我们使用该对象时,才进行创建
-->
<bean id="userDao" class="com.qf.dao.impl.UserDaoImpl" init-method="InitMethod" destroy-method="destroyMethod" scope="prototype" lazy-init="true" ></bean>
</beans>
2.4spring整合mybatis的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">
<!-- <bean id="shopService" class="com.qf.service.impl.ShopServiceImpl">-->
<!-- <property name="shopDao" ref="shopDao"></property>-->
<!-- </bean>-->
<!-- 扫描你的包结构,当spring扫描包是,发现类上如果加入了有关 spring 的注解,就会执行操作-->
<context:component-scan base-package="com.qf"></context:component-scan>
<!-- 导入properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- datasource 配置
org.springframework.jdbc.datasource.DriverManagerDataSource jdbc的数据源
-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${name}"></property>
<property name="password" value="${password}"></property>
</bean>
<!--sqlSessionFactroy 配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.qf.pojo"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource2"></property>
<property name="typeAliasesPackage" value="com.qf.pojo"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
<!--插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor"></bean>
</array>
</property>
</bean>
<!--
id 必须为mapperScannerConfigurer
-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--
通过反射的方式创建sqlsessionFactory,当配置文件中只有唯一的一个sqlSessionFactory时,可以不用加载
-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<!--
将dao交给Spring管理
-->
<property name="basePackage" value="com.qf.dao"></property>
</bean>
</beans>
2.5spring aop面向切面编程
aop切面编程时的spring配置
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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">
<bean id="userService" class="com.qf.service.impl.UserServiceImpl"></bean>
<!-- 通知-->
<bean id="before" class="com.qf.aopHandel.BeforeHandle"></bean>
<bean id="after" class="com.qf.aopHandel.AfterHandle"></bean>
<bean id="throwing" class="com.qf.aopHandel.AfterThrowingHandle"></bean>
<bean id="afterfinal" class="com.qf.aopHandel.AfterFinalHandle"></bean>
<bean id="aroundHandle" class="com.qf.aopHandel.AroundHandle"></bean>
<!-- 将切面类交给spring-->
<bean id="myAspect" class="com.qf.aopAspect.MyAsepect"></bean>
<!-- 配置aop-->
<!--
execution() 切点表达式
* 默认
* 最外层的包名 com
* 下层包名 qf
* 通常为service包名
* impl
* impl包中的类
* 类中的方法
(..) 任意参数
-->
<aop:config>
<!-- 前置通知 advice-ref="前置通知类" pointcut="切点表达式"-->
<!-- <aop:advisor advice-ref="before" pointcut="execution(* *.*.*.*.*(..))"></aop:advisor>-->
<!-- <!– 后置通知 –>-->
<!-- <aop:advisor advice-ref="after" pointcut="execution(* *.*.*.*.*(..))"></aop:advisor>-->
<!-- <!– 异常通知 与后置通知只会执行一个–>-->
<!-- <aop:advisor advice-ref="throwing" pointcut="execution(* *.*.*.*.*(..))"></aop:advisor>-->
<!-- 环绕通知 -->
<!-- <aop:advisor advice-ref="aroundHandle" pointcut="execution(* *.*.*.*.*(..))"></aop:advisor>-->
<aop:pointcut id="myPoint" expression="execution(* *.*.*.*.*(..))"/>
<aop:aspect ref="myAspect">
<!-- <aop:before method="before" pointcut-ref="myPoint"></aop:before>-->
<!-- <aop:after-returning method="afterReturing" pointcut-ref="myPoint"></aop:after-returning>-->
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="myPoint"></aop:after-throwing>-->
<!-- <aop:after method="after" pointcut-ref="myPoint"></aop:after>-->
<aop:around method="around" pointcut-ref="myPoint"></aop:around>
</aop:aspect>
</aop:config>
</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: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
https://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">
<context:component-scan base-package="com.qf"></context:component-scan>
<!--开启aop的注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- dataSource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${name}"></property>
<property name="password" value="${password}"></property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.qf.pojo"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
</bean>
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<property name="basePackage" value="com.qf.dao"></property>
</bean>
<!-- 开启aop注解模式-->
<!-- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>-->
<aop:config>
<aop:pointcut id="poi" expression="execution(* *.*.service.impl.*.*(..))"/>
<aop:aspect ref="myAspect">
<aop:around method="around" pointcut-ref="poi"></aop:around>
</aop:aspect>
</aop:config>
<!-- 引入事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务控制-->
<tx:advice transaction-manager="dataSourceTransactionManager" id="tx">
<tx:attributes>
<!--
transfer 发生异常以后 进行回滚操作
-->
<tx:method name="transfer" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 交给aop来进行回滚-->
<aop:advisor advice-ref="tx" pointcut="execution(* *.*.service.impl.*.*(..))"></aop:advisor>
</aop:config>
<!-- 注解管理事务-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
</beans>
五种通知:环绕通知可以理解外另外四种通知的整合
五种通知:
1.前置通知,实现MethodBeforeAdvice接口,重写before方法
2.后置通知,实现AfterReturningAdvice接口,重写afterReturning方法
3.异常通知,实现ThrowAdvice接口,接口源码有四种方法,任选一种进行实现
4.最终通知,找到再补
5.环绕通知,实现MethodIntercepetor接口,重写invoke方法
代码示例
1.前置通知
package com.qf.aopHandel;
import org.aopalliance.aop.Advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* 前置通知
*/
public class BeforeHandle implements MethodBeforeAdvice {
//在方法执行前进行执行
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("我是前置通知");
}
}
2.后置通知
package com.qf.aopHandel;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterHandle implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置通知");
}
}
3.异常通知
package com.qf.aopHandel;
import org.aspectj.lang.annotation.AfterThrowing;
import org.springframework.aop.ThrowsAdvice;
public class AfterThrowingHandle implements ThrowsAdvice {
public void afterThrowing(Exception ex){
System.out.println("发生异常"+ex.getMessage());
}
}
4.最终通知
5.环绕通知
package com.qf.aopHandel;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundHandle implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object proceed =null;
try {
System.out.println("前置通知");
proceed=invocation.proceed();
System.out.println("后置通知");
}catch (Exception e){
System.out.println("异常通知");
}finally {
System.out.println("最终通知");
}
return proceed;
}
}
通知还可以自定义切面的方法实现,常规和注解方式两种
package com.qf.aopAspect;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 自定义切面
*/
public class MyAsepect {
public void before(){
System.out.println("前置通知");
}
public void afterReturing(){
System.out.println("后置通知");
}
public void afterThrowing(){
System.out.println("异常通知");
}
public void after(){
System.out.println("最终通知");
}
public Object around(ProceedingJoinPoint point){
Object proceed=null;
try {
System.out.println("前置");
proceed = point.proceed();
System.out.println("后置");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常");
} finally {
System.out.println("最终");
}
return proceed;
}
}
package com.qf.aopAspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//标注当前类是切面类
//@Aspect
//@Component
public class MyAspectAnno {
//切点表达式
@Pointcut(value = "execution(* *.*.service.impl.*.*(..))")
public void pt1(){
}
// @Before("pt1()")
// public void before(){
// System.out.println("前置通知");
// }
// @AfterReturning("pt1()")
// public void afterReturing(){
// System.out.println("后置通知");
// }
// @AfterThrowing("pt1()")
// public void afterThrowing(){
// System.out.println("异常通知");
// }
// @After("pt1()")
// public void after(){
// System.out.println("最终通知");
// }
@Around("pt1()")
public Object around(ProceedingJoinPoint point){
Object proceed=null;
try {
System.out.println("前置");
proceed = point.proceed();
System.out.println("后置");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常");
} finally {
System.out.println("最终");
}
return proceed;
}
}
2.6spring 事务管理
spring事务管理的配置,即当方法异常时进行事务回滚,不在通过原生方法进行
非注解
<!-- 引入事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务控制-->
<tx:advice transaction-manager="dataSourceTransactionManager" id="tx">
<tx:attributes>
<!--
transfer 发生异常以后 进行回滚操作
-->
<tx:method name="transfer" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
注解
<!-- 引入事务管理器-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<aop:config>
<!-- 交给aop来进行回滚-->
<aop:advisor advice-ref="tx" pointcut="execution(* *.*.service.impl.*.*(..))"></aop:advisor>
</aop:config>
<!-- 注解管理异常-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
2.7较全的spring-context的配置
<?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">
<!-- 扫描-->
<context:component-scan base-package="com.qf"></context:component-scan>
<!-- 导入jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${name}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- sqlsessionFacotry-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.qf.pojo"></property>
<property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor"></bean>
</array>
</property>
</bean>
<!-- spring与mybatis 整合-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.qf.dao"></property>
</bean>
<bean id="myAspect" class="com.qf.config.MyTest"></bean>
<!-- 开启aop注解模式-->
<!-- <aop:aspectj-autoproxy></aop:aspectj-autoproxy>-->
<aop:config>
<aop:pointcut id="poi" expression="execution(* *.*.service.impl.*.*(..))"/>
<aop:aspect ref="myAspect">
<aop:around method="around" pointcut-ref="poi"></aop:around>
</aop:aspect>
</aop:config>
<!-- <!– 事务–>-->
<!-- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">-->
<!-- <property name="dataSource" ref="dataSource"></property>-->
<!-- </bean>-->
<!-- <!– 开启注解的事务–>-->
<!-- <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>-->
</beans>
3.spring-mvc
mybatis完成了dao的impl,spring完成了对象的创建,spring-mvc则需完成对controller层的控制,完成servlet的功能
3.1spring-mvc和web.xml的配置
spring-mvc
<?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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--加载spring-context.xml ,先整合spring和mybatis而后导入springmvc进行三者整合-->
<import resource="classpath:spring-context.xml"></import>
<!-- 必须加入,启动mvc的注解驱动-->
<mvc:annotation-driven/>
<!-- 扫描controller层-->
<context:component-scan base-package="com.qf.controller"/>
<!--视图解析器,当后天响应完成时,根据试图解析器找到响应前端页面的位置-->
<mvc:view-resolvers>
<bean id="viewResolvers" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!-- 后缀-->
<property name="suffix" value=".jsp"></property>
</bean>
</mvc:view-resolvers>
<!-- 静态资源交由默认servlet处理,而不被DispatcherServlet处理,它会将静态资源当做普通资源拦截处理-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!-- 文件上传 bean标签是将当前对象交给spring进行处理-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
<!-- 配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/js/**"/>
<bean class="com.qf.config.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
web.xml
在联网生产的maven-web项目中,会出现"报错",是因为idea检错等级太高,手动调低就可以,不调也不影响
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 加载spring-mvc.xml-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</context-param>
<!-- 配置 DispatcherServlet 前端核心控制器-->
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 映射-->
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 验证码 -->
<servlet>
<servlet-name>cap</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<init-param>
<param-name>kaptcha.border</param-name>
<param-value>no</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>4</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</param-value>
</init-param>
<init-param>
<param-name>kaptcha.background.clear.to</param-name>
<param-value>211,229,237</param-value>
</init-param>
<init-param>
<!-- session.setAttribute("captcha","验证码") -->
<param-name>kaptcha.session.key</param-name>
<param-value>captcha</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>cap</servlet-name>
<url-pattern>/captcha</url-pattern>
</servlet-mapping>
<!-- 中文乱码-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3.2关于七牛云上传文件到云
前端获取文件
<!--上传文件类型必须加enctype="multipart/form-data"-->
<form action="/shop/update" method="post" enctype="multipart/form-data">
图片选择:<img src="${requestScope.shop.shopPic}">
<input type="file" name="file">
<input type="submit">
</form>
后端处理前端传来的文件
使用工具类,参考七牛云官网开发者文档,CV即可
package com.qf.utlis;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class UploadUtils {
public static String upload(MultipartFile multipartFile){
//构造一个带指定 Region 对象的配置类
Configuration cfg = new Configuration(Region.region0());
//...其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传
String accessKey = "m7mFmCTX55PMNPkEBaOLFQMLxW4ZFfZwf2EBm1M2";
String secretKey = "dn220PqIs813-IYrIZtzO_bGLXPo3QSVNep6wNty";
String bucket = "xa-2106";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = null;
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket);
try {
Response response = uploadManager.put(multipartFile.getInputStream(),key,upToken,null, null);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
//返回结果是可以在web查看已上传到七牛云中的图片
//"http://qzvjywkis.hd-bkt.clouddn.com/"是自己七牛云上查看图片的地址
return "http://qzvjywkis.hd-bkt.clouddn.com/"+putRet.hash;
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
3.3restufl编程规范
简言之,restufl规范就是值,前端传给后端,后端响应给前端的数据都是json类型的数据
实现方法
前端传给后端时,可以使用序列化的方法将数据转为json
以一个ajax为例
$.ajax({
url:"${pageContext.request.contextPath}/user/login",
method:"post",
data:JSON.stringify({userName:username,password:password}),
contentType:"application/json",
dataType:"json",
success:function (res){
alert(res);
}
})
后端接收实现
package com.qf.controller;
import com.qf.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RequestMapping("/user")
@RestController
//@ResponseBody + @Controller 当前类下的所有接口返回的都是 json串
public class UserController {
/**
* @RequestBody 将json串转为对象格式
* @ResponseBody 将返回的内容转为json格式
* @param user
* @return
*/
//@RequestMapping(value = "/login",method = RequestMethod.POST)
@PostMapping("/login")
public String login(@RequestBody User user){
System.out.println(user);
return "{code:1}";
}
//@RequestMapping(value = "/del",method = RequestMethod.DELETE)
@DeleteMapping("/del")
public String del(@RequestBody Map map){
Object id = map.get("id");
System.out.println(id);
return "{code:1}";
}
//
// @RequestMapping(value = "/update",method = RequestMethod.PUT)
@PutMapping("/update")
public String update(@RequestBody Map map){
Object id = map.get("id");
Object name = map.get("name");
System.out.println(id);
System.out.println(name);
return "{code:1}";
}
}
4.SSM常用注解
1.@Component、@Service、@Repository、@Controller
- @Component:是一个通用的Spring容器管理的单例bean组件,最普通的组件,可以被注入到spring容器进行管理。`@Component`是通用注解,其他三个注解是这个注解的拓展,并且具有了特定的功能。
- @Service:作用于业务逻辑层(service层)
- @Repository:作用于持久层(dao层),它注解的类作为DAO对象(数据访问对象,Data Access Objects),这些类可以直接对数据库进行操作
- Controller:作用于表现层(spring-mvc的注解),它注解的类进行前端请求的处理,转发,重定向。包括调用Service层的方法。
2.@RequestMapping
- 使用在controller层,可放在类或方法上,是一个用来处理请求地址映射的注解,在类上,表示该类下的所有方法都以此地址作为父类路径映射
- 该注解有6个属性:
1.value,method:
value:指定请求的实际地址,指定的地址可以是URI Template 模式;
method:指定请求的method类型, GET、POST、PUT、DELETE等;
2.consumes,produces:
consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;当该类或方法有@ResposeBody,使用此进行解决中文乱码,设置可能出现406错误,意味,所传的数据前台无法解析.
3.params,headers;
params:指定request中必须包含某些参数值是,才让该方法处理。
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。
- spring 4.3映入了方法级注解变体,也叫@RequsetMapping组合注解,可更好的表达被注解方法的语义.也就是不用单独设置请求方法
1.@GetMapping 就是get和RequestMapping的组合 以此类推其余三种
2.@PsotMapping
3.@PutMapping
4.@DeleteMapping
3.@Resources和@Autowired、@Qualifier
- @Resources:是有java提供的注解,import javax.annotation.Resources;
- @Autowired和@Qualifier是由spring提供的注解
- 二者都是用来实现依赖注入,就是通过spring来获得对象
对于@Resources注解: 有两个常用属性name、type, Spring将name属性解析为bean的名字,而type属性则被解析为bean的类型。
对于@Autowired和@Qualifier: 当Dao和Servic层只有一个Resposity和sertvice注解时,表示当前需要被注入的对象是唯一的,但是当有多个时,可以通过给Resposity和sertvice注解设置value值来实现唯一确定某一个类,所以在注入时就用到了@Qualifier注解来设置当前类的注解名称
4.@RequestBody、@ResposeBody和@ResquestParam
- @RequestBody、@ResposeBody注解可以将前端传的对象,后台响应给前端的对象转为json串的格式,以此更好的满足restufl编码规范
@RequestBody: 表示可以将前端传来的json串转为对象的形式
例如:
@PostMapping("/login")
public String login(@RequestBody User user){
System.out.println(user);
return "{code:1}";
}
- 值得注意的是,当前端使用$.ajax传送时,必须指定传的数据格式是json格式
- 所有需要设置 contentType: "application/json;charset=utf-8;",
- 默认为 application/x-www-form-urlencoded。
contentType是默认值因为传的数据格式不是json串所以不可以使用@RequsetBody
- 所以此时就得使用@RequestParam注解,即使url?后的参数都可以获取使用
@PostMapping("/login")
public String login(@RequestParam Map map){
System.out.println(user);
return "{code:1}";
}
- @ResposeBody,将后台请求的数据对象转为json的格式传给前端,注意的是一定要是对象!或者json串.当前端使用$.ajax请求时,需要设置dataType:"json",返回值类型是json才可
在controller层,@ResposeBody+@Controller = @RestController
的语义.也就是不用单独设置请求方法
1.@GetMapping 就是get和RequestMapping的组合 以此类推其余三种
2.@PsotMapping
3.@PutMapping
4.@DeleteMapping
### 3.@Resources和@Autowired、@Qualifier
```markdown
- @Resources:是有java提供的注解,import javax.annotation.Resources;
- @Autowired和@Qualifier是由spring提供的注解
- 二者都是用来实现依赖注入,就是通过spring来获得对象
对于@Resources注解: 有两个常用属性name、type, Spring将name属性解析为bean的名字,而type属性则被解析为bean的类型。
对于@Autowired和@Qualifier: 当Dao和Servic层只有一个Resposity和sertvice注解时,表示当前需要被注入的对象是唯一的,但是当有多个时,可以通过给Resposity和sertvice注解设置value值来实现唯一确定某一个类,所以在注入时就用到了@Qualifier注解来设置当前类的注解名称
4.@RequestBody、@ResposeBody和@ResquestParam
- @RequestBody、@ResposeBody注解可以将前端传的对象,后台响应给前端的对象转为json串的格式,以此更好的满足restufl编码规范
@RequestBody: 表示可以将前端传来的json串转为对象的形式
例如:
@PostMapping("/login")
public String login(@RequestBody User user){
System.out.println(user);
return "{code:1}";
}
- 值得注意的是,当前端使用$.ajax传送时,必须指定传的数据格式是json格式
- 所有需要设置 contentType: "application/json;charset=utf-8;",
- 默认为 application/x-www-form-urlencoded。
contentType是默认值因为传的数据格式不是json串所以不可以使用@RequsetBody
- 所以此时就得使用@RequestParam注解,即使url?后的参数都可以获取使用
@PostMapping("/login")
public String login(@RequestParam Map map){
System.out.println(user);
return "{code:1}";
}
- @ResposeBody,将后台请求的数据对象转为json的格式传给前端,注意的是一定要是对象!或者json串.当前端使用$.ajax请求时,需要设置dataType:"json",返回值类型是json才可
在controller层,@ResposeBody+@Controller = @RestController