目录
即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .
大纲要点:1 掌握常用坐标dependency的含义,如web,热部署等。
2 所有讲授过的注解及其含义和用法;
3 理解和应用IOC的原理和注入方式,AOP的原理和应用;
4 掌握MVC应用方法,能够使用自动注入实现类托管;
5 掌握mybatis的常用配置项,能够使用全局和映射文件方式,以及注解方式使用mybatis;
6 掌握前端基本控件及表单的使用方法,能够做到前后端交互;’
常用的坐标dependency的含义
<!--从父依赖那继承版本号,下面省略此注释-->
<!--生产准备的特性,用于帮你监控和管理应用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--对面向切面变成的支持,通过spring-aop和AspectJ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--对java持久化API的支持,包括Spring-data-jpa,spring-orm和Hibernate-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--对JDBC数据库的支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
SpringBoot要求,项目要继承SpringBoot的起步依赖spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
<dependency>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--对Thymeleaf模板引擎的支持,包括和Spring的集成--><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf></artifactId></dependency>
<!-- springboot热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
封装打包依赖坐标提供默认功能便于快速开发配置
本质上是一个Maven项目对象模型(Project Object Model,POM),
定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。
简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能
常用注解及其含义
启动注解 @SpringBootApplication
@SpringBootConfiguration 注解,
继承@Configuration注解,主要用于加载配置文件
@EnableAutoConfiguration 注解,
开启自动配置功能
@ComponentScan 注解,
主要用于组件扫描和自动装配
,@RestController注解
相当于@ResponseBody+@Controller合在一起的作用,不让他们走视图解析器了。
@RequestBody
@RequestBody的作用是将前端传来的json格式的数据转为自己定义好的javabean对象
@ResponseBody
@ResponseBody的作用是将后端以return返回的javabean类型数据转为json类型数据。在此就不做具体的事例演示
RequestMapping(value = "/say",method = RequestMethod.GET)等价于:@GetMapping(value = "/say")
@PathVariable:获取url中的数据
@RequestParam:获取请求参数的值
@Repository
@Repository的作用:
这是因为该注解的作用不只是将类识别为Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。 Spring本身提供了一个丰富的并且是与具体的数据访问技术无关的数据访问异常结构,用于封装不同的持久层框架抛出的异常,使得异常独立于底层的框架。
@Service
- 使用注解配置和类路径扫描时,被@Service注解标注的类会被Spring扫描并注册为Bean
- @Service是@Component注解的一个特例,作用在类上
、 @AutoWired
byType 方式。把配置好的 Bean 拿来用,完成属性、方法的组装,它可以对类成员变量、方法及构
造函数进行标注,完成自动装配的工作。
当加上(required=false )时,就算找不到 bean 也不报错。
@Component
@Component是一个元注解,意思是可以注解其他类注解,如@Controller @Service @Repository。带此注解的类被看作组件,当使用基于注解的配置和类路径扫描的时候,这些类就会被实例化。其他类级别的注解也可以被认定为是一种特殊类型的组件,比如@Controller 控制器(注入服务)、@Service服务(注入dao)、@Repository dao(实现dao访问)。@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注,作用就相当于 XML配置,<bean id="" class=""/>。
@Controller 通常是被使用服务于web 页面的。默认,你的controller方法返回的是一个string 串,是表示要展示哪个模板页面或者是要跳转到哪里去。
@RestController 就是专门用在编写API的时候,特别那种返回一个JSON,或者是XML等等。然后方法返回的是可以是一个对象,是一个可以被序列化的对象。
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面分成三类进行说明。
value, method
value: 指定请求的实际地址,指定的地址可以是具体地址、可以RestFul动态获取、也可以使用正则设置;
method: 指定请求的method类型, 分为GET、POST、PUT、DELETE等;
consumes,produces
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
params,headers
params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
IOC设计思想以及相关源代码
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
IOC创建对象的方式
1、User.java
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
2、beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="kuangshen"/>
</bean>
</beans>
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//在执行getBean的时候, user已经创建好了 , 通过无参构造
User user = (User) context.getBean("user");
//调用对象的方法 .
user.show();
}
结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!
有参构造方式创建对象
1、UserT . java
public class UserT {
private String name;
public UserT(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
2、beans.xml 有三种方式编写
<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>
@Test
public void testT(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserT user = (UserT) context.getBean("userT");
user.show();
}
结论:在配置文件加载的时候。其中管理的对象都已经初始化了!
DI注入
DI注入
DI注入概念
依赖注入(Dependency Injection,DI)。
依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .
构造器注入
我们在之前的案例已经讲过了
Set 注入 (重点)
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .
1、常量注入
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
</bean>
测试:
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
2、Bean注入
注意点:这里的值是一个引用,ref
<bean id="addr" class="com.kuang.pojo.Address">
<property name="address" value="重庆"/>
</bean>
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
</bean>
3、数组注入
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
</bean>
4、List注入
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>
5、Map注入
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>
6、set注入
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>
7、Null注入
<property name="wife"><null/></property>
8、Properties注入
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>
Spring中bean有三种装配机制,分别是:
在xml中显式配置;
在java中显式配置;
隐式的bean发现机制和自动装配。
这里我们主要讲第三种:自动化的装配bean。
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。
推荐不使用自动装配xml配置 , 而使用注解 .
autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
测试:
public class User {
private Cat cat;
private Dog dog;
private String str;
}
1、修改bean配置,增加一个属性 autowire="byName"
<bean id="user" class="com.kuang.pojo.User" autowire="byName">
<property name="str" value="yuanyuhao"/>
</bean>
- 再次测试,结果依旧成功输出!
- public class MyTest {
- @Test
- public void testMethodAutowire() {
- ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
- User user = (User) context.getBean("user");
- }
autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
测试:
1、修改bean配置,增加一个属性 autowire="byName"
<bean id="user" class="com.kuang.pojo.User" autowire="byName">
<property name="str" value="yuanyuhao"/>
</bean>
- 再次测试,结果依旧成功输出!
小结:
当一个bean节点带有 autowire byName的属性时。
将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
去spring容器中寻找是否有此字符串名称id的对象。
如果有,就取出注入;如果没有,就报空指针异常。
使用注解自动装配bean
使用注解
jdk1.5开始支持注解,spring2.5开始全面支持注解。
准备工作:利用注解的方式注入属性。
1、在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
2、开启属性注解支持!
<context:annotation-config/>
@Autowired
@Autowired是按类型自动转配的,不支持id匹配。
需要导入 spring-aop的包!
测试:
1、将User类中的set方法去掉,使用@Autowired注解
public class User {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String str;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getStr() {
return str;
}
}
2、此时配置文件内容
<context:annotation-config/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
3、测试,成功输出结果!
AOP思想
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
提供声明式事务;允许用户自定义切面
以下名词需要了解下:
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
目标(Target):被通知对象。
代理(Proxy):向目标对象应用通知之后创建的对象。
切入点(PointCut):切面通知 执行的 “地点”的定义。
连接点(JointPoint):与切入点匹配的执行点。
即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .
使用Spring实现Aop
【重点】使用AOP织入,需要导入一个依赖包!
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
第一种方式(使用springAPI)
第一种方式
通过 Spring API 实现
首先编写我们的业务接口和实现类
public interface UserService {
public void add();
public void delete();
public void update();
public void search();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
@Override
public void search() {
System.out.println("查询用户");
}
}
然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强
public class Log implements MethodBeforeAdvice {
//method : 要执行的目标对象的方法
//objects : 被调用的方法的参数
//Object : 目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
//method被调用的方法
//args 被调用的方法的对象的参数
//target 被调用的目标对象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + target.getClass().getName()
+"的"+method.getName()+"方法,"
+"返回值:"+returnValue);
}
}
最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!--aop的配置-->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.search();
}
}
Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .
Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 .
第二种方式(自定义类)
第二种方式
自定义类来实现Aop
目标业务类不变依旧是userServiceImpl
第一步 : 写我们自己的一个切入类
public class DiyPointcut {
public void before(){
System.out.println("---------方法执行前---------");
}
public void after(){
System.out.println("---------方法执行后---------");
}
}
去spring中配置
<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/>
<!--aop的配置-->
<aop:config>
<!--第二种方式:使用AOP的标签实现-->
<aop:aspect ref="diy">
<aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before pointcut-ref="diyPonitcut" method="before"/>
<aop:after pointcut-ref="diyPonitcut" method="after"/>
</aop:aspect>
</aop:config>
测试:
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
第三种方式(使用注解实现)
第一步:编写一个注解实现的增强类
package com.kuang.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
第二步:在Spring配置文件中,注册bean,并增加支持注解的配置
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
aop:aspectj-autoproxy:说明
通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。
当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,
但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了
<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,
当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。
不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
SpringMVC自动注入实现类托管
/**\
* SpringMVC自动注入
* @author Administrator
*
*/
@Controllerpublic class DemoController {
/**
* SpringMVC很厉害,有自动注入的功能,当form表单中值的name与实体类的
* 属性名一样时,会自动注入实体类,如果不一样,会设为实体类里的属性设
* 置一个null值,如果实体类里有基本数据类型,不能设置为null,则报错400
* @param product
*/
@RequestMapping("demo1")
public void demo1(Product product) {
System.out.println(product);
}
/**
* 如果前端传过来的值的名称与参数的名称相同,SpringMVC会自动注入
* 如果名称不相同,可以通过注解来解决
* RequestParam("value") value 为前端传过来值的名称
* @param name
* @param price
*/
@RequestMapping("demo2")
public void demo2(@RequestParam("name") String name1,@RequestParam("price")int price1) {
System.out.println(name1+" "+price1);
}
/**
* 加上required后代表该属性一定要被赋值,否则报错
* @param name
* @param price
*/
@RequestMapping("demo3")
public void demo3(@RequestParam(required=true)String name,@RequestParam()int price) {
System.out.println(name+" "+price);
}
}
/**
* 当浏览器传过来有多个同名参数时,用一个集合来接收,并且使用@RequestParam
*/
@RequestMapping("demo4")
public String demo4(@RequestParam("hover")List<String> list) {
System.out.println(list);
//跳转到login.jsp
return "/login.jsp";
}
当浏览器传的值要赋给类里面的类属性时:
<a href="demo5?teacher.name=teacherName">show!!</a>
控制器方法:
/**
* 浏览器传来的值要赋给一个类里的对象属性时
*/
@RequestMapping("demo5")
public String demo5(Student studnet) {
System.out.println(studnet);
return "/login.jsp";
}
Student class:
public class Student {
private String name;
private Teacher teacher;
当浏览器传的值要赋给类里面的集合时:
表单:
<form action="demo6" method="get">
<input type="text" name="teacherList[0].name">
<input type="text" name="teacherList[1].name">
<input type="submit" value="add" />
</form>
控制器类:
/**
* 浏览器传来的值要赋给一个类里的对象属性时
*/
@RequestMapping("demo5")
public String demo5(Student studnet) {
System.out.println(studnet);
return "/login.jsp";
}
@RequestMapping("demo6")
public String demo6(Student student) {
System.out.println(student);
return "/login.jsp";
}
实体类Student:
public class Student {
private List<Teacher> teacherList;
MyBatis全局配置文件
一、Mybatis的全局配置文件
1. SqlMapConfig.xml(名称可变)是mybatis的全局配置文件,配置内容如下:
properties(属性)
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
二、Mapper映射文件
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心
Mapper映射文件是一个xml格式文件,必须遵循相应的dtd文件规范,如ibatis-3-mapper.dtd
Mapper映射文件是以作为根节点,在根节点中支持9个元素,分别为insert、update、delete、select(增删改查);cache、cache-ref、resultMap、parameterMap、sql
- select、parameterMap、resultType、resultMap
parameterType(输入类型)
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。
#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。
Mybatis详细执行流程
Resource获取全局配置文件
实例化SqlsessionFactoryBuilder
解析配置文件流XMLCondigBuilder
Configration所有的配置信息
SqlSessionFactory实例化
trasactional事务管理
创建executor执行器
创建SqlSession
实现CRUD
查看是否执行成功
提交事务
关闭
注解开发mybatis
核心
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
//方法存在多个参数,所有的参数必须加@Param
@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);
@Insert("insert into user (id, name, pwd) values" +
"(#{id},#{name},#{password})")
int addUser(User user);
@Update("update user set name=#{name}, pwd=#{password} " +
"where id=#{id}")
int updateUser(User user);
@Delete("delete from user where id=#{id}")
int deleteUser(@Param("id") int id);
}
MybatisUtile
//sqlSessionFactory --> sqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis第一步:获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
}
public class UserDaoTest {
@Test
public void test(){
// 获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
// 1.执行 getmapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
List<User> userList = userDao.getUsers();
for (User user : userList) {
System.out.println(user);
}
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭
sqlSession.close();
}
}
@Test
public void getuserById(){
// 获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
// 1.执行 getmapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
User user = userDao.getUserById(1);
System.out.println(user);
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭
sqlSession.close();
}
}
@Test
public void addUser(){
// 获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
// 1.执行 getmapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
userDao.addUser(new User(6, "kun","123"));
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭
sqlSession.close();
}
}
@Test
public void updateUser(){
// 获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
// 1.执行 getmapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
userDao.updateUser(new User(6, "fang","123"));
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭
sqlSession.close();
}
}
@Test
public void deleteUser(){
// 获得sqlsession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try{
// 1.执行 getmapper
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
userDao.deleteUser(6);
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭
sqlSession.close();
}
}
前后端的表单使用
JS处理json
JS对象 ==> JSON字符串 JSON.stringify(obj)
//obj是一个js对象
var obj = {a: 'Hello', b: 'World'}
//result就变成了一个json字符串了
var result = JSON.stringify(obj);// '{"a": "Hello", "b": "World"}'
JSON字符串 ==> JS对象 JSON.parse(obj)
//json是一个json字符串
var json = '{"a": "Hello", "b": "World"}';
//obj就变成了一个js对象
var obj = JSON.parse(json);// {a: 'Hello', b: 'World'}
JSON数据
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript 规范的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
数据在名称/值对中
数据由逗号分隔(最后一个健/值对不能带逗号)
花括号保存对象,方括号保存数组
键使用双引号
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON数据在不同语言进行传输时,类型为字符串,不同的语言各自也都对应有解析方法,需要解析完成后才能读取
从前端向后台传递参数方法
一、通过表单传递参数
1.前端部分,在前端jsp页面设置form表单,确定需要传递的参数name让用户输入,通过点击按钮后submit()提交到后台
<form id="loginform" name="loginform" action="<%=path %>/login" method="post">
<div class="form-group mg-t20">
<i class="icon-user icon_font"></i>
<input type="text" class="login_input" id="sfzh" name="sfzh" placeholder="请输入用户名" />
</div>
<div class="form-group mg-t20">
<i class="icon-lock icon_font"></i>
<input type="password" class="login_input" id="pwd" name="pwd" placeholder="请输入密码" />
</div>
<div class="checkbox mg-b25">
<label>
<!-- <input type="checkbox" />记住密码 -->
</label>
<span style="color: red;" id="error">
<%
String message = (String)request.getAttribute("message");
if(StringUtils.isNotBlank(message)){
%><%=message %><%
}
%>
</span>
</div>
<button id="login" type="submit" style="submit" class="login_btn">登 录</button>
</form>
2.后台对前端请求的反应,接收数据,处理数据以及返回数据。
@RequestMapping(method=RequestMethod.POST)
public String dologin(String sfzh, String pwd, RedirectAttributes redirectAttributes){
User query = new User();
query.setUserAccount(sfzh);
HttpSession session = HttpSessionUtil.getHttpSession();
List<User> userlist = userService.select(query);
二.通过ajax传递参数(有post和get写法)
1.ajax是如何将前端数据传到后台的
function leftmenu(parentid, parentpath,moduleindex){
var leftcontent="";
$.ajax({
type: "POST",
url : "<%=path%>/resource/usermenus",
data : {parentid:parentid,parentpath:parentpath},
success : function(data){
// 处理head menu是否有页面要打开
leftcontent= template('_menu2tmpl',data);
$('.nav').html(leftcontent);
addclick();
//临时点击显示菜单
if($('.index-left-warp').width()==0){
$(".index-left-show").hide();
$(".index-left-warp").animate({width:"200px"},250);
timer=setTimeout(function(){
tabsResize();
},500);
};
$(".nav").accordion({
//accordion: true,
speed: 500,
closedSign: '<img src="<%=path%>/images/menu_close.png"/>',
openedSign: '<img src="<%=path%>/images/menu_open.png"/>'
});
}
});
}
$.ajax({undefined
type: "POST",//type是ajax的方法
url : "<%=path%>/resource/usermenus",//参数url,要把参数传到什么地方
data : {parentid:parentid,parentpath:parentpath},//传递什么数据
success : function(data){//sucess表示,当数据返回成功后要怎么做,返回的数据存储在data
2.后台对前端请求的反应,接收数据,
@ResponseBody
@RequestMapping(value = "usermenus")
public Map<String, Object> usermenus(String parentid, String parentpath) {
UserDetail user = HttpSessionUtil.getSessionUser();
String appadmin = Config.getInstance().getCustomValue("app.admin");
List<Resource> list = null;
if(user.getUserAccount().equals(appadmin)){
// 系统内置管理员 默认获取全部授权
list = resourceservice.queryAllMenuCascade(parentpath);
}else{
list = resourceservice.queryUserMenuCascade(user.getId(), parentpath);
}
// 初始化根节点
Resource root= new Resource();
root.setId(parentid);
Collections.sort(list, new Comparator<Object>() {
public int compare(Object o1, Object o2) {
Resource resource1 = (Resource) o1;
Resource resource2 = (Resource) o2;
if (resource1.getSort() > resource2.getSort()) {
return 1;
}
if (resource1.getSort() < resource2.getSort()) {
return -1;
}
//如果返回0则认为前者与后者相等
return 0;
}
});
// 组装Tree
return RecDHTree(root,list);
}
3.再看看前端接收到后端返回的数据是如何处理的
function leftmenu(parentid, parentpath,moduleindex){
var leftcontent="";
$.ajax({
type: "POST",
url : "<%=path%>/resource/usermenus",
data : {parentid:parentid,parentpath:parentpath},
success : function(data){
// 处理head menu是否有页面要打开
leftcontent= template('_menu2tmpl',data);
$('.nav').html(leftcontent);
addclick();
//临时点击显示菜单
if($('.index-left-warp').width()==0){
$(".index-left-show").hide();
$(".index-left-warp").animate({width:"200px"},250);
timer=setTimeout(function(){
tabsResize();
},500);
};
$(".nav").accordion({
//accordion: true,
speed: 500,
closedSign: '<img src="<%=path%>/images/menu_close.png"/>',
openedSign: '<img src="<%=path%>/images/menu_open.png"/>'
});
}
});
}