作业

SSH和SSM的区别

SSH和SSM的区别

个人认为:
SSH 通常指的是 Struts2 做控制器(Action)。

SSM 则指的是 SpringMVC 做控制器(controller)。

共同点:

1.Spring依赖注入DI来管理各层的组件。

2.使用面向切面编程AOP管理事物、日志、权限等。

不同点:

1.Struts2 和 SpringMVC 控制器(controller)控制视图和模型的交互机制的不同,

2.Struts2是Action类级别,SpringMVC是方法级别,更容易实现RESTful风格。

Spring

1.什么是Spring
Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。

Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。
然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用

它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用,比如说把Struts和hibernate粘合在一起运用。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

  1. 什么是控制反转(或依赖注入)
    控制反转(IoC=Inversion of Control)IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:(依赖)控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。

MVC的设计模式

  1. MVC

首先MVC是M(Model)模型,V(View)视图,C(Controller)控制器,MVC是一种分离显示业务逻辑,数据和界面的一种模式。

  1. MVC设计模式的基本流程

(1)首先通过获得用户request请求(例如:请求查看某某空间)
(2)控制器获得请求后,将用户的请求转交给Model(模型)“数据库管理员”,要求获取某某空间数据
(3)通过控制器下达的指令,Model前往数据库获得相应数据,然后反馈给控制器
(4)控制器将获得的反馈数据,转交给View(视图)“数据美化师”,根据控制器提供的数据,进行相应的美化渲染
(5)View渲染后再次反馈给控制器,再将渲染后的数据反馈给客户的请求。

3.个人理解
MVC之所以被引用,在于他独特的分离显示,模块的分工明显,且不用模块的修改,不会干扰其他模块显示和运作。

Spring MVC

1.Spring MVC是Spring生态圈WebMVC中的一部分。

Spring和SpringMVC的关系
个人理解的SpringMVC是Spring核心功能的衍生物,就像是一个房子,是需要一个核心框架核心地基,在此基础上才能有更好更多的设计和发展。

struts2和SpringMVC的比较
两者和Spring的关系就好比陌生人和表亲,SpringMVC,相对会更贴切Spring,在功能和事件的应用上能更有效地发生联动

ORM程序技术

ORM的概念:ORM是对象(Object)、关系(Relation al)、映射(Mapping)的缩写,是一种用于实现面向对象编程语言里,不同类型系统的数据之间转换的程序。
作用:对象信息变化时,修改数据库中的数据更加方便和易于接受。(无需学习和编写SQL语句,就能改变数据库。)
优势:提高了开发效率。
JDBC连接及操作操作数据库步骤如下:1.注册驱动、2.获取连接、3.获取statement对象、4.执行SQL 语句返回结果集、5.遍历结果集、6.关闭连接释放资源。
缺点:1.某条语句执行失败时,处理逻辑非常复杂。
2.对其中业务逻辑做修改,改动的代码量非常多。

Mybatis简介

1.引入

我们在学完MySQL数据库的基础内容之后,我们就开始学习一下数据库持久化操作的相关内容,那么我们之前也学习过一些相关的内容,如:最基础的JDBC,之后的Dbutils,在之后的JdbcTemplate等这些内容。但是呢我们学习这一些操作在实际的项目开发中对于我们的需求还是不够好。那么下面呢我们就一起来学习一下数据库持久化操作框架MyBatis相关的一下内容。

2.数据库持久化操作对比

(1).Jdbc(Dbutils/JdbcTemplate)进行数据持久化的过程

在这里插入图片描述
(2).Hibernate框架进行数据持久化操作的过程

hibernate是一种全自动的ORM(Object Relation Mapping)框架,也就是他会把每一条数据库的记录和我们的java对象进行一个映射关系。旨在消除SQL,它的操作就是把传统的数据操作自己封装在一个黑匣中,然后我们只要提供数据对象以及所需的HQL,那么我们就可以获取到我们所需的结果。这样就会产生另一些问题:

1.Hibernate自己编写的SQL不一定是最优的SQL,那么当我们发现这一条SQL可以优化的时候,我们无法进行优化的操作。

2.对结果的处理。由于HIbernate的全映射,那么当我们只需要一张数据库表中的部分字段的时候,hibernate会把我们整条记录所有字段都查询出来。这样无疑又把不需要的字段查询出来。(需要学精通HQL才可以完成)
在这里插入图片描述
(3).MyBaits框架进行数据持久化操作的过程
鉴于Hibernate所带来的弊端,MyBat还是类似于Hibernate这样的操作,但是它把编写SQL这一个较为重要的环节通过配置文件的方式可以提供给编写人员自己编写以后优化,然后把其他的环节自己封装。这样就把SQL和java代码分离。这样就能够实现Mybatis半自动的轻量级持久化框架的操作。
在这里插入图片描述
3.MyBatis下载

下载地址:https://github.com/mybatis/mybatis-3
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Spring工程搭建

搭建配置Spring

在IDEA中新建一个项目

在这里插入图片描述
在建好的文件中导入包:
maven仓库查询网址:MavenRepository
spring基础包:
spring-core:Core模块主要包含Spring框架基本的核心工具类,Spring的其他组件要都要使用到这个包里的类,Core模块是其他组件的基本核心
spring-beans:包含访问配置文件、创建和管理bean以及进行IOC/DI操作相关的所有类
spring-context:Spring的上下文即IOC容器,通过上下文可以获得容器中的
Beanspring-expression:EL表达式语言用于在运行时查询和操纵对象
在这里插入图片描述
在这里插入图片描述
目录中这样显示即为导包成功
在这里插入图片描述

编写代码测试

// DemoApplication.java
package com.abloume.springboot.blog.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
// 这里有一个坑,没有注册扫描器,下面分析时会有说明
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

// HelloController.java
package com.abloume.springboot.blog.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController 
// 使用 @RestController 相当于 @Controller 和 @RequestBody
public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
        return "Hello Spring boot!";
    }
}

// DemoApplicationTests
package com.abloume.springboot.blog.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

    @Test
    public void contextLoads() {
    }

}

// HelloControllerTest
package com.abloume.springboot.blog.controller;

import com.abloume.springboot.blog.demo.DemoApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.hamcrest.core.IsEqual.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@RunWith(SpringRunner.class)
@SpringBootTest // 这里有一个配置坑
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;
    @Test
    public void testHello() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Hello Spring boot!")));
    };
};

执行过程分析

下面贴上自己的报错图及解决方案:
在这里插入图片描述
解决方案:

// 这里需要指定它的启动类
@SpringBootTest(classes = DemoApplication.class)

在这里插入图片描述
报错404说明路径错误匹配不到,但前后路径是对应的都是 “/hello”;

再仔细看 HelloController.java 发现未被使用
在这里插入图片描述
解决方案:需要在启动类中添加扫描注解即可
在这里插入图片描述
浏览器上运行看一下,Ok~
在这里插入图片描述

Spring IOC&DI

引入IOC之前

代码实现

User模块实体类:User.java

package entity;

public class User {
    private Integer id;
    private String name;
    private Integer gender;
    // 省略getter&setter方法
}

User模块视图类:UserVo.java

package vo;

public class UserVo {
    private Integer id;
    private String name;
    private Integer gender;
    private String genderName;
    // 省略getter&setter方法
    public UserVo() {
    }
    public UserVo(User user) {
        this.id = user.getId();
        this.name = user.getName();
        this.gender = user.getGender();
    }
    // 省略toString方法
}

User模块Dao层:UserDao.java

package dao;

public interface UserDao {
    User getEntity(Integer id);
}

User模块Dao层实现类:UserDaoImpl.java

package services.impl;

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserVo getVo(Integer id) {
        // 手动实例化Dao
        userDao = new UserDaoImpl();
        // 执行Dao层方法
        User user = userDao.getEntity(id);
        // 省略业务逻辑处理。。。
        UserVo userVo = new UserVo(user);
        userVo.setGenderName(userVo.getGender() == 0 ? "female" : "male");
        return userVo;
    }
}

TIPS: 对于userVo.getGender() == 0 ? “female” : "male"不理解的需要复习一下if判断和三目运算符
User模块Controller层:UserController.java

package controller;

public class UserController {
    private UserService userService;

    public UserVo getVo(Integer id) {
        // 手动实例化Service
        userService = new UserServiceImpl();
        // 执行Service层方法并返回
        return userService.getVo(id);
    }
}

User模块测试类:UserTest.java

public class UserTest {
    public static void main(String[] args) {
        // 手动实例化Controller
        UserController userController = new UserController();
        // 执行Controller层方法
        UserVo userVo = userController.getVo(1);
        System.out.println(userVo);
    }
}

测试结果
测试结果如下图所示:
在这里插入图片描述
表示Dao层数据已经一层层传到Controller层并展示了出来
缺点分析
1.代码耦合性太强 不利于程序的测试
2. 代码也不利于扩展
解决方式:
Spring的IOC完美的解决了这一点

对象的实例化由Spring框架加载实现,放到Spring容器中管理,避免了我们手动new对象

有需要用到对象实例依赖,直接向Spring容器要,让他注入即可

而一旦涉及到对象的实例修改,那么只需更改Spring加载实例化对象的地方,程序代码无需改动

从而降低耦合,提升扩展性

引入IOC(XML)

代码实现
要想使用SpringIOC首先需要导入Spring框架基础包并且添加Spring核心配置文件

将依赖交给Spring的beanFactory管理

<bean id="userDao" class="dao.impl.UserDaoImpl"/>
<bean id="userService" class="services.impl.UserServiceImpl"/>
<bean id="userController" class="controller.UserController"/>

User模块测试类:UserTest.java

读取配置文件刷新Spring容器
Controller由手动实例化改为从Spring容器拿取
把ApplicationContext传到Controller层继续使用

public class UserTest {
    public static void main(String[] args) {
        // 读取配置文件刷新Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        // 从Spring容器拿Controller
        UserController userController = (UserController) context.getBean("userController");
        // 执行Controller层方法,因为之后还需要用到context对象,故下传
        UserVo userVo = userController.getVo(1, context);
        System.out.println(userVo);
    }
}

User模块Controller层:UserController.java

  1. Service由手动实例化改为从Spring容器拿取
  2. 把ApplicationContext传到Service层继续使用
package controller;

public class UserController {
    private UserService userService;

    public UserVo getVo(Integer id, ApplicationContext context) {
        // 从Spring容器拿Service
        userService = (UserService) context.getBean("userService");
        // 执行Service层方法,因为之后还需要用到context对象,故下传
        return userService.getVo(id, context);
    }
}

User模块Service层实现类:UserServiceImpl.java

Dao由手动实例化改为从Spring容器拿取

package services.impl;

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserVo getVo(Integer id, ApplicationContext context) {
        // 从Spring容器拿Dao
        userDao = (UserDao) context.getBean("userDao");
        // 执行Dao层方法
        User user = userDao.getEntity(id);
        // 省略业务逻辑处理。。。
        UserVo userVo = new UserVo(user);
        userVo.setGenderName(userVo.getGender() == 0 ? "female" : "male");
        return userVo;
    }
}

测试结果

测试结果如下图所示:
在这里插入图片描述
表示已经将所有的依赖由手动实例化改为从Spring容器拿取

缺点分析

因为每一个类的实例化都需要一个bean标签,一个大型工程有很多类,配置文件的内容未免过于臃肿,维护成本高

解决方式

使用注解形式实现SpringIOC

XML改注解(IOC)

核心配置文件修改

context-component-scan标签Spring框架自定义的xml标签,通过base-package属性指明需要被自动扫描实例化的类所在位置

如下代码所示,我们在dao、services、controller下的类是需要扫描自动注入容器的

<?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:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        https://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
       ">

    <!-- bean definitions here -->
    <context:component-scan base-package="dao"/>
    <context:component-scan base-package="services"/>
    <context:component-scan base-package="controller"/>

</beans>

修改好后运行项目发现context.getBean()代码报错
在这里插入图片描述
说明不是在base-package下的所有类都会自动注入到容器,而是要搭配注解使用

常用注解介绍

  • @Component:一般用于通用组件类上使用的注解
  • @Service:一般用于业务逻辑层上使用的注解
  • @Controller:一般用于流程控制层上使用的注解
  • @Repository:一般用于数据持久层上使用的注解

依次添加注解,添加之后运行再次报错找不到bean
在这里插入图片描述
其实我们在添加注解后,Spring会默认给每个bean设置id,值为类名首字母改为小写

这次报错原因就是找不到名为”userService“的bean

解决办法就是在注解时设置bean的id,保证可以找到bean
在这里插入图片描述
测试结果

测试结果如下图所示:
在这里插入图片描述

引入DI

上面所有的内容都是将对象放入Spring容器中

那么放入之后的使用呢,目前都是使用ApplicationContext拿取容器中的对象

接下来讲解如何使用注解实现依赖注入

常用注解介绍

@Autowired注解自动按照类型注入

会从容器中寻找符合依赖类型的实例,但是也有缺点:

因为时按照类型匹配,如果找不到匹配的实例也会抛出异常

如果容器中有多个匹配的类型也会抛出异常,需要指定引入的实例id

@Qualifier注解作用是在按照类型注入的基础之上,再按照Bean的id注入。所以如果是使用了@Autowire注解自动注入,但是容器中却有多个匹配的实例,可以搭配此注解,指定需要注入的实例id

@Resource注解作用是指定依赖按照id注入,还是按照类型注入。当只使用注解但是不指定注入方式的时候,默认按照id注入,找不到再按照类型注入。

代码实现

User模块Controller层:UserController.java

package controller;

@Controller
public class UserController {
    // 改为自动注入
    @Autowired
    private UserService userService;

    public UserVo getVo(Integer id, ApplicationContext context) {
        // 执行Service层方法,因为之后还需要用到context对象,故下传
        return userService.getVo(id, context);
    }
}

User模块Dao层实现类:UserDaoImpl.java

去除指定bean id,改为默认bean id(userDaoImpl)

package dao.impl;

// 改为默认bean id“userDaoImpl”
@Repository
public class UserDaoImpl implements UserDao {
    public User getEntity(Integer id) {
        // 此处应该从数据库查询值 方便起见直接返回一个固定对象
        User user = new User();
        user.setId(1);
        user.setName("Anne");
        user.setGender(0);
        return user;
    }
}

User模块Service层实现类:UserServiceImpl.java

改为自动注入并指定需要注入的实例id

package services.impl;

@Service("userService")
public class UserServiceImpl implements UserService {
    // 改为自动注入并指定需要注入的实例id
    @Autowired
    @Qualifier("userDaoImpl")
    private UserDao userDao;

    public UserVo getVo(Integer id) {
        // 执行Dao层方法
        User user = userDao.getEntity(id);
        // 省略业务逻辑处理。。。
        UserVo userVo = new UserVo(user);
        userVo.setGenderName(userVo.getGender() == 0 ? "female" : "male");
        return userVo;
    }
}

测试结果

测试结果如下图所示:
在这里插入图片描述
表示

@Autowired注解已将UserService依赖自动注入UserController
@Qualifier注解已指定UserDao依赖的bean id,并使用@Autowired注解自动注入UserServiceImpl

SpringAOP

代理模式

在学习Spring的过程中,留下一下痕迹。
代理模式,其实就是让别人做同样的事情,但是别人却不仅将我的事情做了,还会把他的事情也做了,换言之,这个人做的事情,是他独有的事情和我需要做的事情的综合。回到代码,那么就是,代理类执行与委托类同样的方法,在这方法里代理类不仅可以执行委托类的方法的内容,还可以添加自己的另外的内容,在使用代理类的时候,会比直接使用委托类具有更多的能力,所以我们会直接使用代理类。
通常,代理类虽然具备更多的能力,但是代理类更多的能力其实是比较固定的。例如,在JDBC里,或在ORM框架里,都会存在事务的开启和提交,如果我们直接将事务代码和业务代码写在一起,其实也是可以的,不过,这样做会使得每一个需要事务的方法,都要添加事务代码,造成代码的分散冗余,那么,针对这种情况,我们希望业务代码可以抽离出来,每一个业务方法都只写业务内容,同时我们又希望,在执行业务方法时,可以有一种方式自动添加业务代码,这种需求,其实就是有了代理的需求,因为我们希望还是使用原来的方法,但是出来的效果希望是多出事务代码,也就是希望业务代码得到增强。可以这样理解了,抽离出来的业务代码,是一个委托类,而可以将委托类自动增强并添加事务代码的代码,是一个代理类,它代理执行委托类,具备了委托类原有的业务能力之余,增加了事务处理的代码。
我理解的代理模式,其实就是将委托类融入到代理类里,换句话说,代理类也就是委托类的扩充而已。
还有不仅是spring 的AOP是代理模式,还有Struts2的拦截器实现也是基于动态代理的,动态代理是一种很常见也很重要的设计模式。
说了很多,那么如何实现代理,那我们先说说静态代理。

静态代理
一个接口,两个实现类,代理实现类组合真实实现类
静态代理,是一种根据上面的理论,很自然会想到的一种不依赖于其他技术的代理模式实现方式。而他的实现过程如下图。
在这里插入图片描述

如果使用过静态代理,那么很容易理解,静态代理存在的缺陷。

因此,也就出现了动态代理。

动态代理的动态, 就是可以动态的切换真实实现类, 也就是说可以一个代理类(相同的代码, 相同的增强操作)应对一堆不确定的真实实现类.

动态代理
JDK动态代理和CGlib字节码动态代理
1.2.1 JDK动态代理(必须有接口)
通过java.lang.reflect.Proxy类实现。
动态代理就是为了解决静态代理不灵活的缺陷而产生的。静态代理是固定的,一旦确定了代码,如果委托类新增一个方法,而这个方法又需要增强,那么就必须在代理类里重写一个带增强的方法。而动态代理可以灵活替换代理方法,动态就是体现在这里。
在这里插入图片描述

public interface TargetClass {
    void sayHello();
}

public class TargetClassImpl implements TargetClass{
    public void sayHello() {
        System.out.println("你好");
    }
}

public class JdkProxy implements InvocationHandler {
    private TargetClass targetClass;
    public Object createProxy(TargetClass targetClass){
        //传入真实实现类, 本身要做的事情会由他自己做, 代理类会额外进行其他增强操作
        this.targetClass = targetClass; 
        //获取本类类加载器
        ClassLoader classLoader = JdkProxy.class.getClassLoader();
        ///获取被代理对象的所有接口
        Class[] clazz = targetClass.getClass().getInterfaces();
        System.out.println(clazz.length);
        //生成代理类并返回
        return Proxy.newProxyInstance(classLoader, clazz, this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDKProxy前置增强");
        Object obj = method.invoke(targetClass,args);
        System.out.println("JDKProxy后置增强");
        return obj;
    }
}

public class Test {
    public static void main(String[] args) {
		JdkProxy jdkProxy = new JdkProxy();
		TargetClass targetClass = new TargetClassImpl();
		TargetClass targetClass1 = (TargetClass) jdkProxy.createProxy(targetClass);
		targetClass1.sayHello();
}

######1.2.2 CGlib动态代理(不需要类继承任何接口,字节码技术)
CGlib包在Spring core包里。
在这里插入图片描述

public class CGlibTaretClass {
    public void sayHello(){
        System.out.println("我是CGlib,我不需要接口");
    }
}

package CGlibProxyTest;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CGlibProxy implements MethodInterceptor{
    //代理方法
    public Object createProxy(Object target){
        //创建一个动态类对象
        Enhancer enhancer = new Enhancer();
        //确定要增强的类,设置期父类
        enhancer.setSuperclass(target.getClass());
        //添加回调函数
        enhancer.setCallback(this);
        //返回创建的代理类
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CGlib前置增强");
        Object obj = methodProxy.invokeSuper(o,objects);
        System.out.println("CGlib后置增强");
        return obj;
    }
}


public class Test {
    public static void main(String[] args) {
		CGlibProxy cGlibProxy = new CGlibProxy();
        CGlibTaretClass cGlibTaretClass = new CGlibTaretClass();
        CGlibTaretClass cGlibTaretClass1 = (CGlibTaretClass)cGlibProxy.createProxy(cGlibTaretClass);
        cGlibTaretClass1.sayHello();
   }

简单转账功能

编写properties文件

jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.jdbcUrl = jdbc:mysql://localhost:3306/spring
jdbc.user = root
jdbc.password = 123456

dao层编写

package com.xf.dao;

/**
 * @author xfgg
 */
public interface AccountDao {
    /*
    汇款
     */
    public void out(String outUser,int money);
    /*
    收款
     */
    public void in(String inUser,int money);
}


package com.xf.dao.impl;

import com.xf.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;


/**
 * @author xfgg
 */
public class AccountDaoImpl implements AccountDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
        this.jdbcTemplate=jdbcTemplate;
    }
    @Override
    public void out(String outUser, int money) {
        this.jdbcTemplate.update("update account set money =money-?"
                + "where username =?",money,outUser);
    }

    @Override
    public void in(String inUser, int money) {
        this.jdbcTemplate.update("update account set money =money+?"
                +"where username=?",money,inUser);
    }
}


service层编写

package com.xf.service;

public interface AccountService {

    public void transfer(String outUser,String inUser,int money);
}

package com.xf.service.impl;

import com.xf.dao.AccountDao;
import com.xf.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao){
        this.accountDao=accountDao;
    }
    @Override
    public void transfer(String outUser, String inUser, int money) {
        this.accountDao.out(outUser,money);
        this.accountDao.in(inUser,money);
    }
}

编写application.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.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-2.5.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <!--扫描注解-->
    <context:component-scan base-package="com.xf.dao"/>
    <context:component-scan base-package="com.xf.service"/>
    <!--加载properties文件-->
    <context:property-placeholder location="c3p0-db.properties"/>
    <!--配置数据源,读取properties文件信息-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--配置事务管理器,依赖于数据源-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <!-- 给切入点方法添加事务详情,name表示方法名称,
            *表示任意方法名称,propagation用于设置传播行为,read-only表示隔离级别,是否只读 -->
            <tx:method name="find*" propagation="SUPPORTS" rollback-for="Exception"/>
            <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
        </tx:attributes>
    </tx:advice>
    <!--aop编写,让spring自动对目标生成代理,需要使用Aspectj的表达式-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="txPointCut" expression="execution(* com.xf.service.*.*(..))"/>
        <!--切面:将切入点和通知整合-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>

编写Test方法

package com.xf.test;

import com.xf.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author xfgg
 */
public class AccountTest {
    @Test
    public void test(){
        String xmlPath = "applicationContext.xml";
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext(xmlPath);
        AccountService accountService = (AccountService) applicationContext.getBean("accountService");
        accountService.transfer("aaa","bbb",100);
    }
}

使用注解方式进行事务管理
修改application.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"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-2.5.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-2.5.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
        <!-- 加载properties文件 -->
        <context:property-placeholder location="classpath:c3p0-db.properties" />
        <!-- 配置数据源,读取properties文件信息 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driverClass}" />
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
            <property name="user" value="${jdbc.user}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
        <!-- 配置jdbc模板 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <!-- 配置dao -->
        <bean id="accountDao" class="com.xf.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate" />
        </bean>
        <!-- 配置service -->
        <bean id="accountService" class="com.xf.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao" />
        </bean>
        <!-- 事务管理器,依赖于数据源 -->
        <bean id="txManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <!-- 注册事务管理驱动 -->
        <tx:annotation-driven transaction-manager="txManager"/>
    </beans>

修改AccountServiceImpl方法

    package com.mengma.service.impl;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    import com.mengma.dao.AccountDao;
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
    public class AccountServiceImpl {
        private AccountDao accountDao;
        public void setAccountDao(AccountDao accountDao) {
            this.accountDao = accountDao;
        }
        public void transfer(String outUser, String inUser, int money) {
            this.accountDao.out(outUser, money);
            // 模拟断电
            int i = 1 / 0;
            this.accountDao.in(inUser, money);
        }
    }

引入代理模式解决事务

静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.

举例:
保存用户(模拟)
Dao , 直接保存
DaoProxy, 创建代理对象,给保存方法添加事务处理

代码示例:
接口:

// 接口
public interface IUserDao {

void save();

}
目标对象实现接口

public class UserDao implements IUserDao{

@Override
public void save() {
    System.out.println("-----已经保存数据!!!------");
}

}
代理对象实现接口,并扩展目标对象的功能(添加事务处理)

public class UserDaoProxy implements IUserDao{

// 接收保存目标对象
private IUserDao target;
public UserDaoProxy(IUserDao target) {
    this.target = target;
}

@Override
public void save() {
    System.out.println("开始事务...");

    target.save();          // 执行目标对象的方法

    System.out.println("提交事务...");
}

测试,通过调用代理对象的方法,实现对目标对象保存的扩展。

public class App {

public static void main(String[] args) {
    // 目标对象
    IUserDao target = new UserDao();

    // 代理
    IUserDao proxy = new UserDaoProxy(target);
    proxy.save();  // 执行的是,代理的方法
}

}
总结:
静态代理可以做到在不修改目标对象的功能的前提下,对目标对象功能进行扩展。这也符合面向对象设计原则之开闭原则:对扩展开发,对修改关闭。
缺点:
(1)需要定义太多代理类
因代理对象需要和目标对象实现相同的接口。所以会有很多的代理类需要定义。
(2)不方便维护
因为一但用户定义接口需要增加额外的方法,目标对象与代理对象都要修改,代码写死,维护成本过高。

因此解决办法就是代理工厂,使用动态代理的方式。

动态代理

动态代理概念
1)代理对象不需要实现接口,但是目标对象必须实现接口,因为要指定接口类型;
2)代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类;);
3) 动态代理也叫做JDK代理, 接口代理;

JDK中生成代理对象的API:

|-- Proxy
static Object newProxyInstance(
ClassLoader loader, 指定当前目标对象使用的类加载器
Class<?>[] interfaces, 目标对象实现的接口的类型
InvocationHandler h 事件处理器
)
代码示例:
接口类IUserDao.java以及接口实现类,目标对象UserDao是一样的,没有做修改.在这个基础上,增加一个代理工厂类(ProxyFactory.java),将代理类写在这个地方,然后在测试类(需要使用到代理的代码)中先建立目标对象和代理对象的联系,然后代用代理对象的中同名方法。

代理工厂类:ProxyFactory.java

public class ProxyFactory {

// 维护一个目标对象
private Object target;
public ProxyFactory(Object target){
    this.target = target;
}

// 给目标对象,生成代理对象  
public Object getProxyInstance() {
    return Proxy.newProxyInstance(
            target.getClass().getClassLoader(), 
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    System.out.println("开启事务");

                    // 执行目标对象方法
                    Object returnValue = method.invoke(target, args);

                    System.out.println("提交事务");
                    return returnValue;
                }
            });
}

}
测试App.java

public class App {

public static void main(String[] args) {
    // 目标对象
    IUserDao target = new UserDao();
    // 【原始的类型 class com.nwpu.geeker.UserDao】
    System.out.println(target.getClass());

    // 给目标对象,创建代理对象
    IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
    // 类型:class $Proxy0   内存中动态生成的代理对象
    System.out.println(proxy.getClass());

    // 执行方法   【代理对象】
    proxy.save();
}

}
动态代理总结:
代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能用动态代理!

思考:
有一个目标对象,想要功能进行扩展,但目标对象没有实现接口,怎样功能扩展?

Class  UserDao{}
// 通过子类的方式
Class subclass  extends  UserDao{}

使用cglib代理。通过运行时期创建子类扩展目标对象的方法。

cglib代理

Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。

CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

代码示例:

public class UserDao {

public void save() {
    System.out.println("-----已经保存数据!!!------");
}

}
cglib代理实现

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**

  • Cglib子类代理工厂

  • (对UserDao 在内存中动态构建一个子类对象)
    */
    public class ProxyFactory implements MethodInterceptor{

    // 维护目标对象
    private Object target;
    public ProxyFactory(Object target){
    this.target = target;
    }

    // 给目标对象创建代理对象
    public Object getProxyInstance(){
    //1. 工具类
    Enhancer en = new Enhancer();
    //2. 设置父类
    en.setSuperclass(target.getClass());
    //3. 设置回调函数
    en.setCallback(this);
    //4. 创建子类(代理对象)
    return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args,
    MethodProxy proxy) throws Throwable {

     System.out.println("开启事务.....");
    
     // 执行目标对象的方法
     Object returnValue = method.invoke(target, args);
    
     System.out.println("提交事务.....");
    
     return returnValue;
    

    }

}
Cglib子类代理:

  1. 需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。
    2)引入功能包后,就可以在内存中动态构建子类
    3)代理的类不能为final, 否则报错。
    4) 目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法。

总结:
在Spring的AOP编程中,
如果加入容器的目标对象有实现接口,用JDK代理;
如果目标对象没有实现接口,用Cglib代理;

引入AOP

引入就是在一个接口的基础上引入新的接口增强功能。

在上一篇博客中测试AOO的时候,我们打印了用户信息,如果用户信息为空,则抛出异常。

事实上,我们还可以检测用户信息是否为空,如果为空则不再打印,这样就没有异常产生了。

但现有的UserService接口并没有提供这样的功能,这里假定UserService这个服务并不是自己所提供,而是别人提供的,我们不能修改它,这时Spring还允许增强这个接口的功能,我们可以为这个接口引入新的接口。例如,要引入一个用户检测的接口UserValidator,定义如下

UserValidator接口

package com.lay.springboot_aop.aspect.validator;

import com.lay.springboot_aop.aspect.pojo.User;

public interface UserValidator {
    public boolean validate(User user);
}


UserValidatorImpl实现类

package com.lay.springboot_aop.aspect.validator.impl;

import com.lay.springboot_aop.aspect.pojo.User;
import com.lay.springboot_aop.aspect.validator.UserValidator;

public class UserValidatorImpl implements UserValidator {
    
    @Override
    public boolean validate(User user) {
        System.out.println("引入新的接口" + UserValidator.class.getSimpleName());
        return user != null;
    }
    
}


这样,我们通过Spring AOP引入的定义就能够增强UserService接口的功能,然后我们在切面类中加入如下代码

MyAspect切面

package com.lay.springboot_aop.aspect;


@Aspect
public class MyAspect {
    
    @DeclareParents(value = "com.lay.springboot_aop.aspect.service.impl.UserServiceImpl*", defaultImpl = UserValidatorImpl.class)
    public UserValidator userValidator;
    
    @Pointcut("execution(* com.lay.springboot_aop.aspect.service.impl.UserServiceImpl.printUser(..))")
    public void pointCut() {
    }
    
    @Before("pointCut()&&args(user)")
    public void before(JoinPoint point ,User user) {
        Object[] args=point.getArgs();
        User a= (User)args[0];
        System.out.println("print in before"+user.getUserName());
        System.out.println("\nprint in before args = "+a.getUserName());
        System.out.println("before-----------");
    }
    
    @Around("pointCut()")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("around before-------------");
        jp.proceed();
        System.out.println("around after-------------");
    }
    
    @After("pointCut()")
    public void after() {
        System.out.println("after------------");
    }
    
    @AfterReturning("pointCut()")
    public void afterReturning() {
        System.out.println("afterReturning------------");
    }
    
    @AfterThrowing("pointCut()")
    public void afterThrowning() {
        System.out.println("afterThrowning------------");
    }
}


这里我们看到了一个新的注解@DeclareParents,它的作用是引入新的类来增强服务,但它有两个必须配置的属性value和defalutImpl。

value:指向你要增强功能的目标对象,这里要增强UserServiceImpl对象
defaultImpl:引入增强功能的类,这里配置为UserValidatorImpl,用来提供校验用户是否为空的功能。

测试
UserController

package com.lay.springboot_aop.aspect.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.lay.springboot_aop.aspect.pojo.User;
import com.lay.springboot_aop.aspect.service.UserService;
import com.lay.springboot_aop.aspect.validator.UserValidator;

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService=null;
    
    @RequestMapping("/vap")
    @ResponseBody
    public User validateAndPrintUser(Integer id,String userName,String message) {
        User user=new User();
        user.setId(id);
        user.setUserName(userName);
        user.setMessage(message);
        UserValidator userValidator=(UserValidator)userService;
        if(userValidator.validate(user)) {
            userService.printUser(user);
        }
        return user;
    }
}


然后启动工程,在浏览器输入http://localhost:8080/user/vap?id=1&userName=username&message=somemessage

XML改注解

修改bean.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"
       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">

    <!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为context名称空间和约束中-->
    <context:component-scan base-package="com.lzyy"></context:component-scan>

    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
        <!--配置QueryRunner-->
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的必备信息-->
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8&amp;serverTimezone=GMT"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

</beans>

修改代码
1.业务层
修改前后对比图:
在这里插入图片描述
2.持久层
修改前后对比图:
在这里插入图片描述

MyBatis工程搭建

JDBC连接及操作数据库

我们需要在MySQL中创建一个table,以供我们测试使用。

CREATE TABLE student(
	ID VARCHAR(5),
	name VARCHAR(20),
	age int(3),
	FM VARCHAR(1),
	PRIMARY KEY(ID)
)

表格效果如下图:
在这里插入图片描述
有了数据库之后,建好maven工程,然后需要配置数据源。在Spring的JDBC框架中,数据源配置在Beans.xml中,当然这个文件名可以随便取的。

整个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-4.1.xsd ">
	
    <bean id="datasource"
     	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    	<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    	<!--注意一下&characterEncoding要修改为&amp;characterEncoding-->
	<property name="url" value="jdbc:mysql://localhost:3306/mysql?useUnicode=true&amp;characterEncoding=utf-8"/>    	
    	<property name="username" value="root"/>
    	<property name="password" value="snow" />
	</bean>   	
	
	<bean id="studentDaoImp"
		class="SNOW.SpringJDBCtest.StudentDaoImp">
		<property name="datasource" ref="datasource" />
	</bean>    	
    	
</beans>

在这里有一点要注意characterEncoding前面的 & 需要更换成 & ,否则会报错。

接下来我们为数据库student创建一个类student.java

package SNOW.SpringJDBCtest;
 
public class Student{
	private String ID;
	private String name;
	private int age;
	private String FM;
	
	public Student(){		
	}
	
	public Student(String ID,String name,int age, String FM){
		this.ID = ID;
		this.name = name;
		this.age = age;
		this.FM = FM;
	}
	
	public void setID(String ID){
		this.ID = ID;
	}
	
	public String getID(){
		return this.ID;
	}
 
	public void setname(String name){
		this.name = name;
	}
	
	public String getname(){
		return this.name;
	}
 
	public void setage(int age){
		this.age = age;
	}
	
	public int getage(){
		return age;
	}
	
	public void setFM(String FM){
		this.FM = FM;
	}
	
	public String getFM(){
		return this.FM;
	}	
	
	public void display(){
		System.out.println(ID + " " + name + " " + age + " " + FM);
	}
	
	
}

有了Student类之后,还需要一个将SQL数据与student对象映射的类StudentMapper.java

package SNOW.SpringJDBCtest;
 
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
 
public class StudentMapper implements RowMapper<Student> {
 
	public Student mapRow(ResultSet rs, int rownum) throws SQLException {
		Student student = new Student();
		student.setID(rs.getString("ID"));
		student.setname(rs.getString("name"));
		student.setage(rs.getInt("age"));
		student.setFM(rs.getString("FM"));
		
		return student;		
	}
	
}

Spring JDBC框架是通过DAO(Data Access Object)来实现对数据库的读写数据操作的,并且在实现过程中应该由应用程序implements interface 来完成数据库的读写操作。

我们的接口定义如下:

package SNOW.SpringJDBCtest;
 
import java.util.List;
import javax.sql.DataSource;
 
 
public interface StudentDao{
 
	/** 
	 * This is the method to be used to initialize
	 * database resources ie. connection.
	 */	
	public void setdatasource(DataSource ds);	
	
	public void addstudent(Student student);
	
	public void delstudentbyID(String ID);
	
	public void delstudentbyname(String name);
	
	public void delallstudent();
	
	public void updstudent(Student student);
	
	public List<Student> allstudent();
	
	public List<Student> querystudentbyID(String ID);
	
	public List<Student> querystudentbyname(String name);
	
	public List<Student> querystudentbyage(int age);
	
	
}

接口实现定义如下:

package SNOW.SpringJDBCtest;
 
import java.util.List;
 
import javax.sql.DataSource;
 
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
 
 
public class StudentDaoImp implements StudentDao{
 
	private DataSource datasource;
	private JdbcTemplate jdbcTemplateObject;
	
	
	public void setdatasource(DataSource ds) {
		this.datasource = ds;
		this.jdbcTemplateObject = new JdbcTemplate(datasource);		
	}
 
	public void addstudent(Student student) {
		String sql = "INSERT INTO class.student(ID,name,age,FM)VALUES(?,?,?,?)";
		
		jdbcTemplateObject.update(sql, student.getID(),
				student.getname(),student.getage(),student.getFM());
		return ;
	}
 
	public void delstudentbyID(String ID) {
		String sql = "DELETE FROM class.student WHERE ID=?";
		jdbcTemplateObject.update(sql,ID);
		return ;
	}
 
	public void delstudentbyname(String name) {
		String sql = "DELETE FROM class.student WHERE name=?";
		jdbcTemplateObject.update(sql,name);
		return ;		
	}
 
	public void delallstudent() {
		String sql = "DELETE FROM class.student";
		jdbcTemplateObject.update(sql);
		return ;	
	}
 
	public void updstudent(Student student) {
		String sql = "UPDATE class.student set name=?,age=?,FM=? WHERE ID=?";
		jdbcTemplateObject.update(sql,student.getname(),
				student.getage(),student.getFM(),student.getID());
		return ;
	}
 
	public List<Student> allstudent() {
		List<Student> students = null;
		String sql = "SELECT * FROM class.student";
		students = jdbcTemplateObject.query(sql, new StudentMapper());
		return students;
	}
 
	public List<Student> querystudentbyID(String ID) {
		List<Student> students = null;
		String sql = "SELECT * FROM class.student WHERE ID=?";
		students = jdbcTemplateObject.query(sql, new Object[]{ID}, new StudentMapper());
		return students;
	}
 
	public List<Student> querystudentbyname(String name) {
		List<Student> students = null;
		String sql = "SELECT * FROM class.student WHERE name=?";
		students = jdbcTemplateObject.query(sql, new Object[]{name}, new StudentMapper());
		return students;
	}
 
	public List<Student> querystudentbyage(int age) {
		List<Student> students = null;
		String sql = "SELECT * FROM class.student WHERE age=?";
		students = jdbcTemplateObject.query(sql, new Object[]{age}, new StudentMapper());
		return students;
	}
	
	public void displayall(){
		List<Student> students = allstudent();
		for(Student s : students){
			s.display();
		}
	}
	
	
}

实现了StudentDaoImp类之后需要装备到Beans.xml中,具体见最上面的Beans.xml代码。

写完以上代码就写完了主要的功能操作了,接下来我们写个测试程序Maintest.java

package SNOW.SpringJDBCtest;
 
import java.util.List;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class Maintest{
	public static void main(String [] args){
		ApplicationContext context = 
				new ClassPathXmlApplicationContext("SNOW/SpringJDBCtest/Beans.xml");
		StudentDaoImp studentDaoImp = (StudentDaoImp)context.getBean("studentDaoImp");
		
		
		String[] ID = { "2008", "2009", "2010", "1990", "2015","2018" };
		String[] name = { "Wang", "Hui", "Yu", "Yuan", "Yuan", "Yang"};
		int[] age = { 16, 18, 20, 20, 22, 21 };
		String[] FM = {"F", "F", "M", "M", "M", "F"};		
		Student student = null;
		List<Student> students = null;
		
		System.out.println("---------addstudent-------------");
		for(int i=0; i<ID.length; i++){
			student = new Student(ID[i],name[i],age[i],FM[i]);
			studentDaoImp.addstudent(student);			
		}
		studentDaoImp.displayall();
		
		System.out.println("---------updatestudent-------------");
		student = new Student("1990","Yuan",18,"M");
		studentDaoImp.updstudent(student);
		studentDaoImp.displayall();
		
		System.out.println("---------querystudentbyID-------------");
		students = studentDaoImp.querystudentbyID("1990");
		for(Student s : students){
			s.display();
		}
		
		System.out.println("---------querystudentbyname-------------");
		students = studentDaoImp.querystudentbyname("Yuan");
		for(Student s : students){
			s.display();
		}
		
		System.out.println("---------querystudentbyage-------------");
		students = studentDaoImp.querystudentbyage(20);
		for(Student s : students){
			s.display();
		}	
		
		System.out.println("---------delstudentbyage-------------");
		studentDaoImp.delstudentbyID("2018");
		studentDaoImp.displayall();
		
		System.out.println("---------delstudentbyname-------------");
		studentDaoImp.delstudentbyname("Hui");
		studentDaoImp.displayall();		
		
		System.out.println("---------delallstudent-------------");
		studentDaoImp.delallstudent();	
		
		
	}
	
}

因为创建的Maven项目,其中pom.xml如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>SNOW</groupId>
  <artifactId>SpringJDBCtest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>SpringJDBCtest</name>
  <url>http://maven.apache.org</url>
 
  <properties>  	
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <dependencies>  	
    <dependency>
      	<groupId>junit</groupId>
      	<artifactId>junit</artifactId>
      	<version>3.8.1</version>
      	<scope>test</scope>
    </dependency>
    
 	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.35</version>
	</dependency>
 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
 
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>4.1.6.RELEASE</version>
	</dependency>
	
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-tx</artifactId>  <!--spring transaction-->
		<version>4.1.6.RELEASE</version>
	</dependency>    
	
  </dependencies>
</project>

最终运行结果如下:

五月 29, 2015 8:51:29 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@384e57ba: startup date [Fri May 29 20:51:29 CST 2015]; root of context hierarchy
五月 29, 2015 8:51:30 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [SNOW/SpringJDBCtest/Beans.xml]
五月 29, 2015 8:51:31 下午 org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
信息: Loaded JDBC driver: com.mysql.jdbc.Driver
---------addstudent-------------
1990 Yuan 20 M
2008 Wang 16 F
2009 Hui 18 F
2010 Yu 20 M
2015 Yuan 22 M
2018 Yang 21 F
---------updatestudent-------------
1990 Yuan 18 M
2008 Wang 16 F
2009 Hui 18 F
2010 Yu 20 M
2015 Yuan 22 M
2018 Yang 21 F
---------querystudentbyID-------------
1990 Yuan 18 M
---------querystudentbyname-------------
1990 Yuan 18 M
2015 Yuan 22 M
---------querystudentbyage-------------
2010 Yu 20 M
---------delstudentbyage-------------
1990 Yuan 18 M
2008 Wang 16 F
2009 Hui 18 F
2010 Yu 20 M
2015 Yuan 22 M
---------delstudentbyname-------------
1990 Yuan 18 M
2008 Wang 16 F
2010 Yu 20 M
2015 Yuan 22 M
---------delallstudent-------------

spring和mybatis整合需要导入的依赖:

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <!--mybatis的依赖-->
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--mybatis和spring集成的依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--mysql驱动依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!--junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!--  spring依赖  -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>
        <!--spring事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>
        <dependency>
        <!--    spring操作数据库    -->
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.3.RELEASE</version>
        </dependency>
        <!--阿里的连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>
    </dependencies>
    <build>
        <!--目的是把src/main/java目录中的xml文件包含在输出结果中,输出classes中-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

编程式配置方法

MyBatis官方文档中并未详细的介绍如何编程式使用MyBatis,因为编程式配置方法代码有点复杂

但是大家没必要被代码吓退,因为在实际的开发中几乎没有机会去写这段代码,一般都是通过配置文件来拿到配置然后开启会话的

我们之所以讲解编程式配置方法,是因为使用配置文件配置时屏蔽了太多的细节

为了层层递进的介绍MyBatis的基础用法,使大家熟悉MyBatis整体结构,我们需要讲解编程式配置方法

代码实现

删除JDBC连接及操作数据库:JDBCDemo.java

新建编程式配置文件:StartNoXml.java

@SuppressWarnings({"SqlResolve", "SqlNoDataSourceInspection", "Duplicates"})
public class StartNoXml {
    public static void main(String[] args) throws SQLException {
        // 准备jdbc事务类
        JdbcTransactionFactory jdbcTransactionFactory = new JdbcTransactionFactory();
        // 配置数据源
        PooledDataSource dataSource = new PooledDataSource(
                "com.mysql.cj.jdbc.Driver",
                "jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false",
                "root",
                "root");
        // 配置环境,向环境中指定环境id、事务和数据源
        Environment environment = new Environment.Builder("development")
                .transactionFactory(jdbcTransactionFactory)
                .dataSource(dataSource).build();
        // 新建 MyBatis 配置类
        Configuration configuration = new Configuration(environment);
        // 得到 SqlSessionFactory 核心类
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        // 开始一个 sql 会话
        SqlSession session = sqlSessionFactory.openSession();
        // 得到 sql 连接并运行 sql 语句
        PreparedStatement preStatement = session
                .getConnection()
                .prepareStatement("SELECT * FROM user WHERE id = ?");
        preStatement.setInt(1, 1);
        ResultSet result = preStatement.executeQuery();
        // 验证结果
        while (result.next()) {
            System.out.println("username: " + result.getString("username"));
            System.out.println("age: " + result.getString("age"));
        }
        // 关闭会话
        session.close();
    }
}

执行结果

控制台打印结果如下图所示,表示我们已经成功连接数据库并查出了需要的值
在这里插入图片描述

配置文件配置mybatis

代码实现

在resources文件夹下新建配置文件: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>
    <!-- 环境变量 -->
    <environments default="development">
        <environment id="development">
            <!-- 事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- 数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

有了上面编程式 API 的使用经验,那么你一定可以轻松的看懂配置项:

configuration 标签对应 Configuration 类
environment 标签对应 Environment 类
transactionManager 标签对应 JdbcTransactionFactory 类
dataSource 标签对应 PooledDataSource 类
启动类:StartWithXml.java

修改类名为StartWithXml
读取配置文件

InputStream configuration = Resources.getResourceAsStream("mybatis-config.xml");

执行结果

控制台打印结果如下图所示,表示我们已经成功连接数据库并查出了需要的值

mybatis实现mapper配置并查询数据

什么是mapper注解方式使用mapper

在MyBatis工程搭建 中我们主要讲解的是 MyBatis 如何连接数据库,具体执行 SQL 语句使用的是 JDBC 方式

但在实际应用中是不会选择 JDBC 来执行 SQL 的,MyBatis 提供了 Mapper 作为 Java 方法和 SQL 语句之间的桥梁,来帮助我们更好地去使用 SQL

Java 接口方法与 SQL 语句以及 mapper 之间的关系如下图所示:
在这里插入图片描述

XML方式使用mapper

因为MyBatis是一个持久层框架,所以我们在使用之前需要执行如下SQL语句备好数据源

#删除mybatis_demo数据库
drop database if exists mybatis_demo;

#创建mybatis_demo数据库
create database mybatis_demo;

#使用mybatis_demo数据库
use mybatis_demo;

#创建account表
create table user (
    id int auto_increment primary key,
    username varchar(20),
    age int,
    score int
);

#新增数据
insert into user (id, username, age, score) values
(1,'peter', 18, 100), (2,'pedro', 24, 200),
(3,'jerry', 28, 500), (4,'mike', 12, 300),
(5,'tom', 27, 1000);

我们以查询User数据为例感受Mapper引入后和JDBC执行SQL有什么区别

MyBatis 提供了注解和XML两种方式来连接Java方法和SQL语句,首先学习注解方式使用Mapper

select-resultType

代码实现

在UserMapper.xml文件中,我们新增 selectUserById 标签,该 select 标签的作用是:通过id查询用户

<select id="selectUserById" resultType="">
    SELECT * FROM user WHERE id = #{id}
</select>

上面的内容返回的是所有字段值,我们需要自己创建实体类来存储查出来的值

在entity包下创建User实体类:User.java

package entity;

public class User {
    private Integer id;
    private String username;
    private Integer age;
    private Integer score;
    // 省略getter&setter方法
    // 省略toString方法
}

把UserMapper.xml文件中selectUserById标签的返回类型改为上面创建的实体类

resultType="entity.User"

User模块Mapper层:UserMapper.java

/**
 * 通过用户id查询用户信息
 *
 * @param id
 * @return
 */
User selectUserById(Integer id);

User模块测试类:UserTest.java

// 调用通过用户id查询用户信息的方法
User user = mapper.selectUserById(1);
System.out.println(user);

测试结果
在这里插入图片描述

select-resultMap

MyBatis自动帮助我们映射数据库数据和Java对象,其实这是MyBatis在幕后帮我们创建了resultMap对象,我们也可手动定义

代码实现

User模块Mapper层配置文件:UserMapper.xml

<resultMap id="userMap" type="entity.User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
    <result property="score" column="score"/>
</resultMap>

上标签中有和两个子标签

其中标签是主键,其它字段均使用 result 标签来映射

标签有property和column两个属性

其中 property 是 Java 对象中的属性名称,column 是数据表与之对应的字段名称

把UserMapper.xml文件中selectUserById标签的返回类型改为上面创建的resultMap

resultMap="userMap"

测试结果

mybatis操作数据

select单条数据查询

要想使用MyBatis首先需要导入MySQL驱动包、MyBatis框架基础包并且添加MyBatis核心配置文件

首先复习下上个章节的内容

代码实现

在entity包下创建User实体类:User.java

package entity;

public class User {
    private Integer id;
    private String username;
    private Integer age;
    private Integer score;
    // 省略getter&setter方法
    // 省略toString方法
}

在dao包下创建User模块Dao层:UserDao.java

package dao;

public interface UserDao {
    /**
     * 通过用户id查询用户信息
     *
     * @param id
     * @return
     */
    User selectUserById(Integer id);
}

在mybatis-config.xml配置文件中添加上对应的mapper配置

<!-- mapper配置 -->
<mappers>
    <mapper class="dao.UserDao"/>
</mappers>

在resources文件夹下新建dao包,并在其下新建User模块Dao层配置文件:UserDao.xml

<?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="dao.UserDao">
    <select id="selectUserById" resultType="entity.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

新建User模块测试类:UserTest.java

@SuppressWarnings({"Duplicates"})
public class UserTest {
    public static void main(String[] args) throws IOException, SQLException {
        // 读取配置文件
        InputStream configuration = Resources.getResourceAsStream("mybatis-config.xml");
        // 得到 SqlSessionFactory 核心类
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        // 开始一个 sql 会话
        SqlSession session = sqlSessionFactory.openSession();
        // 得到 Dao
        UserDao dao = session.getMapper(UserDao.class);
        // 调用通过用户id查询用户信息的方法
        User user = dao.selectUserById(1);
        System.out.println(user);
        // 关闭会话
        session.close();
    }
}

执行结果在这里插入图片描述

select多条数据查询

代码实现

但是在实际使用时我们常常需要一次性查询多条数据,例如:SELECT * FROM user

User模块Dao层配置文件:UserDao.xml

<select id="selectUserList" resultType="entity.User">
    SELECT * FROM user
</select>

这时要用到List集合装对象来完成多条数据的查询工作,User模块Dao层:UserDao.java

/**
 * 查询所有用户信息
 *
 * @return
 */
List<User> selectUserList();

User模块测试类:UserTest.java

// 调用查询所有用户信息的方法
List<User> userList = dao.selectUserList();
userList.forEach(u -> System.out.println(u));
TIPS: 对于userList.forEach(u -> System.out.println(u));

不理解的需要复习一下for forEach 循环及Lambda表达式使用
执行结果
在这里插入图片描述

insert数据

代码实现

User模块Dao层:UserDao.java

/**
 * 新增用户信息
 *
 * @param user
 * @return
 */
int insertUser(User user);

User模块Dao层配置文件:UserDao.xml

<insert id="insertUser" parameterType="entity.User">
    INSERT INTO user VALUES (#{id},#{username},#{age},#{score})
</insert>

User模块测试类:UserTest.java

// 调用查询所有用户信息的方法
List<User> userListBefore = dao.selectUserList();
userListBefore.forEach(u -> System.out.println(u));
// 创建一个要新增的对象并赋值
User insertUser = new User();
insertUser.setId(6);
insertUser.setUsername("anne");
insertUser.setAge(18);
insertUser.setScore(600);
// 调用新增用户信息的方法
int count = dao.insertUser(insertUser);
// 调用查询所有用户信息的方法
List<User> userListAfter = dao.selectUserList();
userListAfter.forEach(u -> System.out.println(u));

执行结果
在这里插入图片描述

update数据

代码实现

User模块Dao层:UserDao.java

/**
 * 修改用户信息
 *
 * @param user
 * @return
 */
int updateUserById(User user);

User模块Dao层配置文件:UserDao.xml

<update id="updateUserById" parameterType="entity.User">
    UPDATE user SET
    age = #{age},
    username = #{username},
    score = #{score}
    WHERE id = #{id}
</update>

User模块测试类:UserTest.java

// 调用通过用户id查询用户信息的方法
User userBefore = dao.selectUserById(6);
System.out.println(userBefore);
// 把成绩改为900
userBefore.setScore(900);
// 调用修改用户信息的方法
dao.updateUserById(userBefore);
// 调用通过用户id查询用户信息的方法
User userAfter = dao.selectUserById(6);
System.out.println(userAfter);

执行结果

控制台打印结果如下图所示
在这里插入图片描述

delete数据

代码实现

User模块Dao层:UserDao.java

/**
 * 删除用户信息
 *
 * @param id
 * @return
 */
int deleteUserById(Integer id);

User模块Dao层配置文件:UserDao.xml

<delete id="deleteUserById">
    DELETE FROM user WHERE id = #{id}
</delete>

User模块测试类:UserTest.java

// 调用查询所有用户信息的方法
List<User> userListBefore = dao.selectUserList();
userListBefore.forEach(u -> System.out.println(u));
// 调用删除用户信息的方法
int count = dao.deleteUserById(6);
// 调用查询所有用户信息的方法
List<User> userListAfter = dao.selectUserList();
userListAfter.forEach(u -> System.out.println(u));

执行结果

控制台打印结果如下图所示在这里插入图片描述

springmvc工程搭建

springmvc请求映射注解

Spring MVC 提供了以下这些请求映射注解:

请求映射注解 说明 类/方法
@RequestMapping 通用的请求处理 类
@GetMapping 处理 HTTP GET 请求 查询方法
@PostMapping 处理 HTTP POST 请求 新增修改方法
@PutMapping 处理 HTTP PUT 请求 新增修改方法
@PatchMapping 处理 HTTP PATCH 请求 新增修改方法
@DeleteMapping 处理 HTTP DELETE 请求 删除方法
除了 @RequestMapping ,其它类型的注解本质上是 @RequestMapping 的简写形式

比如 @GetMapping 其实可以写为@RequestMapping( method = RequestMethod.GET)

建议在类级别上只使用 @RequestMapping ,用于指定基本路径

而在每个方法上根据方法功能不同使用更具体的请求映射注解

搭建配置文件springmvc

创建项目

使用IDEA创建Maven工程

IDEA配置Maven

我们新建Maven项目名为“springmvc-demo“,设置好Maven版本、配置文件以及Maven仓库

由于SpringMVC在 MVC设计模式 中是作为控制器负责前后端代码的连接,我们首先需要添加WEB文件夹用来存放前端代码

添加web

右键我们的项目名 -> 选择“Add Framework Support”
在这里插入图片描述

编写代码测试

编写Controller层

controller包下新建HelloController类

package controller;

@Controller
public class HelloController {

    @RequestMapping("/hello")
    public String hello(Model model){
        // Model 封装数据
        model.addAttribute("msg","HELLO MY FIRST SPRING MVC PROJECT");

        // 返回的字符串就是视图的名字 会被视图解析器处理
        return "hello";
    }
}

配置Spring容器自动扫描包

将Controller对象放进Spring容器

Spring核心配置文件:applicationContext.xml

<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="controller"/>

编写jsp

WEB-INF包下新建jsp包,jsp包下新建hello.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${msg}
</body>
</html>

编写web.xml

配置前端控制器

<!-- 配置前端控制器 -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

设置启动级别
设置启动级别的代码也写在前端控制器内,数字越小启动越早

1
设置SpringMVC拦截请求

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

用url-pattern中的内容来标识请求拦截:

/ 匹配所有的请求;(不包括.jsp)
/* 匹配所有的请求;(包括.jsp)
为空时所有请求都会被SpringMVC拦截
配置中文乱码过滤器

<!--  乱码过滤 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

运行web项目

打包

file -> Project Structure 打开项目构建管理框

首先删除默认打好的包在这里插入图片描述

运行web项目

运行TomCat

点击绿色的小三角运行TomCat,出现如下内容表示运行成功在这里插入图片描述
在浏览器输入 http://localhost:8080/hello 可以看到页面打印出了我们设置好的值在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值