Fork me on GitHub

ResuFul风格

ResuFul风格

有时我们访问一个网页需要传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.dwx.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class MyController {

@RequestMapping("/h2")
public String Servlet(int a,int b,Model model){
int rest;
rest = a + b;
model.addAttribute("msg","结果为"+rest);
return "hello";
}
}

无参时的情况

如果没有传递参数那么就会报500的错误

如何传参?

在以前的情况直接使用?参数=xx就能完成传参

1
http://localhost:8080/s/h2?a=1&b=3

之前的传参方法但是这种传参方法有个很大的问题:必须知道参数名,很不安全,有SQL注入问题

而且这种情况也使得命令行看起来很凌乱

RestFul风格

此时,如果我们使用下边这种方式,就能通过** \ **来传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.dwx.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class MyController {

@RequestMapping("/hello")
public String helloServlet(Model model){
model.addAttribute("msg","hello SpringMvc-annotation");
return "hello";
}

@RequestMapping("/h2/{a}/{b}")
public String Servlet(@PathVariable int a, @PathVariable int b, Model model){
int rest;
rest = a + b;
model.addAttribute("msg","结果为"+rest);
return "hello";
}
}

1
http://localhost:8080/s/h2/2/3

restful

这就是我理解的RestFul风格

SpringMVC乱码处理问题

SpringMVC乱码处理问题

在实际的开发中,如果前后后端交互时使用的编码器不同,就会出现乱码问题,集中表现为中文乱码问题。

解决这种问题的方法:

  • 编译一个Filter层,并且到web.xml中进行配置。
  • 使用SpringMVC提供的现成的过滤器,直接到web.xml中进行配置。

第一种方法是我们之前使用的方法,此时我们不再复习。

依然通过搭建环境来处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.dwx.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class MyController {

@RequestMapping("/h3")
public String FilterTest(Model model,String name){
System.out.println(name);
System.out.println("进入过滤器测试程序");
model.addAttribute("msg",name);
return "hello";

}
}

此时没有加装过滤器:

1
党文轩

到xml中添加过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

添加了过滤器后:

1
dwx的小天地

SpringMVC使用注解开发

SpringMVC使用注解开发

当我们经历过了Spring的学习和Mybatis学习,我们学到注解开发时就说明这个框架基本学习基础内容结束,

我们看一下普通SpringMVC程序的编写: HelloSpringMVC | dwx-tx的小天地

我们可以通过比较两者的差别来学习这个知识点

依然采用创建项目的方法来学习

第一步 创建Module项目(webApp的)

更换了web.xml的配置

第二步 配置DispatcherServlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--绑定SpringMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC-Servlet.xml</param-value>
</init-param>
<!--设置启动级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

第三步 编写SpringMVC配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
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 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--由于我们时使用的注解开发,因此需要添加配置 扫描要添加注解的包-->
<context:component-scan base-package="com.dwx.controller"/>
<!--让SpringMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--这里我们使用下边这个配置代替 添加处理映射器 添加处理适配器-->
<mvc:annotation-driven/>

<!--编写适配视图解析器-->

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>


</beans>


要点已经写到了注解里

第四步 编写Controller类 使用注解

我们使用@Controller修饰一个类,表示该类继承了Controller接口

我们使用@RequestMappering("xx")修饰一个方法表示执行来自xx的请求的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.dwx.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;


@Controller
public class MyController {

@RequestMapping("/hello")
public String helloServlet(Model model){
model.addAttribute("msg","hello SpringMvc-annotation");
return "hello";
}
}

这里,我们使用model.addAttribute来实现封装数据

我们使用return 来实现重定向

这个指会到Spring.xml中加上视图的修饰一起作为重定向的地址

SpringMVC回顾以前的知识

SpringMVC回顾以前的知识

因为SpringMVC也是一种框架,因此,如果我们学习这个框架我们就需要学习它和我们之前知识的相关性,从这个相关性出发学习这个新知识

回顾Servlet

回顾servlet需要重新搭建合适的环境。

步奏:

  • 创建一个空的父项目
  • 导入父项目的包
  • 创建子项目
  • 加上web配置
  • 编写servlet类
  • 注册servlet
  • 配置Tomcat
  • 执行Tomcat

父类需要的包:

junit spring-webmvc servlet-api jsp-api jstl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--servlet的包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>

servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.dwx.servlet;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
System.out.println(method);
if (method.equals("add")){
resp.sendRedirect("hello.jsp");
req.getSession().setAttribute("msg","正在执行增加程序");

}
if (method.equals("delete")){

resp.sendRedirect("hello.jsp");
req.getSession().setAttribute("msg","正在执行删除程序");

}

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

xml

这个xml可以取找之前笔记的或者博客的,不在这里考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?xml version="1.0" encoding="UTF-8"?>

<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>org.example</groupId>
<artifactId>SpringMVC-02</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>SpringMVC-02 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--mysql依赖-->
<!-- https://mvnrepository.com/artifact/org.wisdom-framework/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>SpringMVC-02</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

HelloSpringMVC

HelloSpringMVC

Spring MVC 用DispatcherServlet处理请求_w3cschool :官方中文文档

初学SpringMVC,这个是一个新的概念,因此使用老方法,通过一个模型来理解和学习。

我们这里使用的SpringMVC使用的是Dispatcherservlet,这个东西的底层还是Servlet

搭建环境

  • 搭建一个Module
  • 导入web
  • 确定导入了springmvc的依赖
  • 注册DispatcherServlet,配置xml
  • 设置关联配置文件
  • 注册control到Spring的xml中

整个程序额结构

搭建一个Module

由于我不会使用普通的Module项目添加web依赖来实现创建webapp,因此我是用传统的直接通过maven搭建web环境。

修改web.xml配置:

1
2
3
4
5
6
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

</web-app>

spring.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">


</beans>


这个xml的配置非常全,可能有点用不到,但是十分方便

导入SpringMVC的依赖

1
2
3
4
5
6
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.16</version>
</dependency>

配置web.xml 注册DispatcherServlet

一下的写法都是固定的,不需要有任何改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<!--初测DispatcherServlet 这是我们提供的固定的接口-->
<servlet>
<servlet-name>Spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

我们这里可以看到有一个<init-param></init-param>配置,因此我们需要去创建一个跟web.xml相配的Spring的xml1文件

创建Spring的xml配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">

<!--添加映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!--添加处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

<!--添加视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>

</beans>


这部分的程序也是固定的,不需要改变的

编写Control类

我们这里已经使用了SpringMVC的固定接口DispatcherServlet,因此我们这里使用Spring给的另一个接口Controller来实现我们的servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.dwx.control;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class mycomtrol implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {

ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg","hello SpringMVC");

modelAndView.setViewName("hello");
return modelAndView;
}
}

程序解析:

创建ModelAndView,通过这个产生的对象来执行我们需要执行的程序

modelView:

  • addObject(“msg”,”value”):这个方法相当与原来的setAttribute()。设置参数个前端用
  • setViewName(“name”),相当于重定向

我们可以看到,在spring.xml配置中有:

1
2
3
4
5
6
7
<!--添加视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>

这里的前缀可以添加到这里的name的前后来表示位置

注册到Spring.xml中

1
2
3
<!--注册control-->

<bean id="/hello" class="com.dwx.control.mycomtrol"/>

之后我们就可以通过这个/hello,来执行程序

SpringAOP的实现

SpringAOP的实现

AOP指的是横向开发,在以前的学习中我们都是习惯于纵向开发,但是横向开发同样重要。之前的横向开发我们使用的是动态代理模式和静态代理模式,今天我们学习Spring中的AOP来实现横向开发,它的核心其实也是动态代理模式

学习AOP前的准备

1.导包

使用AOP需要导aspectjweaver

1
2
3
4
5
6
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>

2.创建学习模型

AOP官网是纯理论的东西,学习一个不熟悉的理论最好的办法就是实践,因此我们通过创建模型的方式学习AOP

搭建一个有“增删改查”功能的模型,以及我们横向开发要给每个方法加日志

使用Spring实现AOP

实现AOP的方式很多,这里我们时使用Spring自带的接口来实现AOP

Spring为我们提供了很多AOP的接口,使用方法就是把要插入的类继承各个位置的接口即可

继承抽象类

例如在方法前加方法:

继承这个接口:MethodBeforeAdvice

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.dwx.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BeforLog implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {

}
}

元素分析:

  • method:要执行的目标对象的方法
  • args:参数
  • target:要执行的目标对象

这里我们要添加的是一个日志功能,具体理论就是通过method.getname()来获得执行的方法的名字即可

例如在方法后加日志:

继承AfterReturningAdvice接口

1
2
3
4
5
6
7
8
9
10
package com.dwx.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class EndLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

}
}

元素分析:

  • method:要执行的目标对象的方法
  • args:参数
  • target:要执行的目标对象
  • returnValue:返回值

把我们创建的类都注册到日志中

  • 注册所有的类
  • 配置AOP
    • 在xml头文件中天界aop的命名空间
    • 在xml中使用<aop:xx>来使用aop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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 id="userService" class="com.dwx.service.UserServiceImpl"/>
<bean id="endBlog" class="com.dwx.log.EndLog"/>
<bean id="beforLog" class="com.dwx.log.BeforLog"/>
<!--注册完的类其实之间没有联系,需要通过xml中的AOP产生联系-->
<aop:config>
<!--切入点,表明切入点-->
<!--这句换其实是固定格式 execution(* * * *) 四个*分别代表包 类 方法 参数 全部作用用* 有限制就添加限制-->
<aop:pointcut id="pointcut" expression="execution(* com.dwx.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<!--这里是注入AOP的地方 advice-ref 是我们要查如的东西 pointcut-ref 是刚才的切口即要插入的地方-->
<aop:advisor advice-ref="beforLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="endBlog" pointcut-ref="pointcut"/>
</aop:config>

</beans>

上边就是AOP注册到XML中的完全体,有注释解释每一步的目的

测试

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.dwx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//注意这里使用的是类似于动态代理模式的AOP
//动态代理模式是作用于接口的 因此我们这里产生的对象类型应为接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
userService.delete();
userService.query();
userService.update();
}
}


结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
【DEBUG】正在执行add方法
增加了一个用户
【DEBUG】add方法执行结束返回值为:null
【DEBUG】正在执行delete方法
删除了一个用户
【DEBUG】delete方法执行结束返回值为:null
【DEBUG】正在执行query方法
查询用户为:****
【DEBUG】query方法执行结束返回值为:null
【DEBUG】正在执行update方法
更新了一个用户的信息
【DEBUG】update方法执行结束返回值为:null

Process finished with exit code 0

使用自定义类实现AOP

上边使用的AOP是使用的Spring的接口,其实还可以通过自定义类注册实现AOP

1.自定义一个类

1
2
3
4
5
6
7
8
9
10
11
package com.dwx.diy;

public class DIY {
public void before(){
System.out.println("==========程序执行开始===========");
}
public void after(){
System.out.println("==========程序执行结束===========");
}
}

2.到xml中进行注册

先注册我们的DIY类

在使用aop把DIY类中的方法切入合适的位置

此时有区别的,使用的是切面技术

1
2
3
4
5
6
7
8
9
10
<aop:config>
<!--切面,即我们的DIY类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.dwx.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>

此时通知中包含了很多的标签,想插入哪里就使用对应的标签插入哪里

元素分析:

  • method: 这个是插入的方法,即切面(DIY类)中的方法
  • 切入点这里的所有代码和上边说的一样

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
==========程序执行开始===========
增加了一个用户
==========程序执行结束===========
==========程序执行开始===========
删除了一个用户
==========程序执行结束===========
==========程序执行开始===========
查询用户为:****
==========程序执行结束===========
==========程序执行开始===========
更新了一个用户的信息
==========程序执行结束===========

Process finished with exit code 0

这边可以看出,我们的DIY类实现的AOP没有使用Spring留下的接口实现的AOP强大

但是核心其实都是动态代理

使用注解实现AOP

和xml配置能被注解代替一样,Spring实现AOP也能通过注解实现

@Aspect修饰一个类,表示这个类就是一个切面

@Before("execution()")其中Before修饰的就是我们要切入的方法,execution()自然指的是接入点

例如:@Before("execution(* com.dwx.service.UserServiceImpl.*(..))")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.dwx.diy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class annount {
@Before("execution(* com.dwx.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("*****************");
}

}

这样子切入后也需要到xml中把这个类进行配置,并且开始自动托管事务: <aop:aspectj-autoproxy/>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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 id="userService" class="com.dwx.service.UserServiceImpl"/>
<bean id="diy" class="com.dwx.diy.DIY"/>

<bean id="annount" class="com.dwx.diy.annount"/>
<aop:aspectj-autoproxy/>

</beans>

这样的代码会很简洁

结果:

1
2
3
4
5
6
7
8
9
10
11
*****************
增加了一个用户
*****************
删除了一个用户
*****************
查询用户为:****
*****************
更新了一个用户的信息

Process finished with exit code 0

Spring整合MyBatis

Spring整合MyBatis

终于,学习Spring进入了尾声,需要Spring整合Mybatis

步骤:

  • 导入相关的jar包
  • 编写程序
  • 测试

Spring整合MyBatis需要的jar包

对于Spring,一个Spring-webmvcaspectjwearer可以解决所有的东西

对于Mybatis,需要mybatis包

由于mybatis是基于永久层的,因此需要mysql数据库相关的包

为了方便操作,还要准备Junit和Lombok的包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<dependencies>
<!--Junit的包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--mysql的包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--mybatis的包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!--Spring的一系类包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.15</version>
</dependency>
<!--aspectjweaver-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.RC3</version>
</dependency>
<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>

</dependencies>

编写一个mybatis程序

第一个mybatis程序 | dwx-tx的小天地

上方我博客里的其他博文回顾mybatis程序的编写,在此不在重复

在mybatis程序中加入Spring

分析:mybatis是对持久层的一个框架,它是Dao层和数据库之间的桥梁,还有一些自己的配置(别名,日志等)

因此我们可以的到,我们spring要整合的东西:

  • 数据库的联结
  • SqlsessionFactory
  • Sqlsession
  • mybatis配置

第一步,创建Spring的xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEnconding=utf8&amp;useSSL=truejdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEnconding=utf8&amp;useSSL=true"/>
<property name="username" value="dwx"/>
<property name="password" value="123456"/>
</bean>
<!--整合SqlsessionFactory-->
<bean id="sqlsessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/dwx/mapper/BlogMapper.xml"/>
</bean>
<!--代替SQLsession-->
<bean id="sqlsession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlsessionFactory"/>
</bean>
</beans>

第二步、创建实体类

因为我们的mybatis是用xml代替实体类实现抽象类的,但是我们的Spring必须使用实体类,因此创建实体类;

但是Mybatis使用时需要的三件套

1
2
3
4
5
6
7
8
9
10
11
12
String config = "mybatis-config.xml";
InputStream input = null;
try {
input = Resources.getResourceAsStream(config);
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(input);
SqlSession sqlSession = build.openSession();


BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

以及被我们整合到Spring中去了,因此这个实体类会有点不一样

我们以后会使用SQLsessionTemple来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.dwx.mapper;

import com.dwx.pojo.Blog;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class BlogMapperImpl implements BlogMapper{

//固定格式
private SqlSessionTemplate sqlSessionTemplate;

public SqlSessionTemplate getSqlSessionTemplate() {
return sqlSessionTemplate;
}

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}

@Override
public List<Blog> getBlogs() {
BlogMapper mapper = sqlSessionTemplate.getMapper(BlogMapper.class);
return mapper.getBlogs();
}
}

第三步,把这个实体类注册到bean里

把这个实体类注册到bean里,以后我们就能直接使用bean来调用这些方法了

完全体的bean.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEnconding=utf8&amp;useSSL=truejdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEnconding=utf8&amp;useSSL=true"/>
<property name="username" value="dwx"/>
<property name="password" value="123456"/>
</bean>
<!--整合SqlsessionFactory-->
<bean id="sqlsessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/dwx/mapper/BlogMapper.xml"/>
</bean>
<!--代替SQLsession-->
<bean id="sqlsession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlsessionFactory"/>
</bean>

<bean id="blogMapper" class="com.dwx.mapper.BlogMapperImpl">
<!--我们写这个实体类时留了一个属性 给这个参数赋值-->
<property name="sqlSessionTemplate" ref="sqlsession"/>
</bean>



</beans>

注意,我们的mapper.xml在Spring中注册了,不需要再到config.xml中注册了

测试:

1
2
3
4
5
6
7
8
9
@Test
public void Spring_MybatisTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-mapper.xml");
BlogMapper blogMapper = context.getBean("blogMapper", BlogMapper.class);
List<Blog> blogs = blogMapper.getBlogs();
for (Blog blog : blogs) {
System.out.println(blog);
}
}

这样mybatis-config.xml中就只剩下一部分的配置如:别名,日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.dwx.pojo"/>
</typeAliases>

</configuration>

这样Mybatis就整合到Spring中去了

Spring声明事务

Spring声明事务

想想一下这样一个场景,我们同时执行多个jdbc,但是其中有一个错误了,java会把后边的程序停掉,但是前边成功的就成功了,这样并不合理。因此我们需要事务来管理这些程序,使得他们中间有一个出现错误就程序停止并且数据库回滚

Spring中声明事务

这种方法就像是在每一次执行方法是添加一个方法来观察他,和AOP类似,因此我们可以使用类似AOP的方法管理它。并且Spring有专门进行事务的标签

在xml中声明开启事务

固定写法:

1
2
3
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>

配置事务

1
2
3
4
5
6
7
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
<!--给那些方法配置事务-->
<tx:attributes>
<tx:method name="add"/>
<!--可以欧多个 也可以是直接使用*代替所有的方法-->
</tx:attributes>
</tx:advice>

将配置好的事务切入

1
2
3
4
5
6
<!--切入事务-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.dwx.mapper.* (..))"/>
<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pointcut"/>
</aop:config>

  • advice-ref:只配置好的要插入的事务
  • pointcut-ref:指配置好的插入点

代理模式

代理模式

代理模式是之前学到的,在这里进行一个系统性的复习,因为前边学的代理模式理解并不深刻,但是代理模式又是SpringAOP的底层逻辑,因此需要重新学习。

代理模式的分类:

  • 静态代理模式
  • 动态代理模式

静态代理模式

代理模式十分抽象,因此我们引用房东–房屋中介–租户模型来解释这个关系

房东--房屋中介--租户模型

代理中的角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后一般会有一些附属操作
  • 客户:访问代理对象的人

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不用去关心一些公共业务
  • 公共事务交给代理角色去处理,实现了业务的分工
  • 公共月舞发生拓展是,方便集中管理

下边我们就用这个模型来模拟一下静态代理模式,看是否与上述特点相同:

模型的搭建:

模型的结构

代码:

抽象接口rent

1
2
3
4
5
6
7
package com.dwx.test01;

public interface rent {
//这是房东和中介都要进行的抽象角色(租房)
void rent();
}

房主Host

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.dwx.test01;

public class Host implements rent{
//对于房东 房东可以有自己的属性 比如这里我们给他属性name
String name;
//房东的抽象角色 出租房屋

@Override
public void rent() {
System.out.println(name+"房东要出租房");
}

public Host(String name) {
this.name = name;
}

public Host() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Host{" +
"name='" + name + '\'' +
'}';
}
}

中介Mid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.dwx.test01;

public class Mid implements rent {
//这里是中介 是中间代理环节
//中介代理房东 因此中介有一个属性是房东
private Host host;
//中介同样要出租房 ,也要继承接口

@Override
public void rent() {
//因为中介是代理房东租房,因此实质上出租房子的还是房东
//因此这里调用房东出租的方法
host.rent();
}

//中介除了执行出租方外,还可以带领住户看房以及签合同,收中介费,因此这些都是中介特有的
//但是是属于每次租房都要干的,是公共的
public void sign() {
System.out.println("中介在签合同");
}

public void see() {
System.out.println("中介在看房");
}

public void fare() {
System.out.println("中介收取中介费");
}

public Mid(Host host) {
this.host = host;
}

public Mid() {
}

public Host getHost() {
return host;
}

public void setHost(Host host) {
this.host = host;
}

@Override
public String toString() {
return "Mid{" +
"host=" + host +
'}';
}
}

中介中心Center

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.dwx.test01;

public class Center {
//这里是中介中心,用户访问的地方
public static void main(String[] args) {
//首先创建一个租户
Host dwx = new Host("dwx");
//再创建一个中介
Mid mid = new Mid();
//给中介分配租户
mid.setHost(dwx);
//中介执行租房操作
mid.see();
mid.sign();
mid.rent();
mid.fare();
}
}

执行结果:

1
2
3
4
中介在看房
中介在签合同
dwx房东要出租房
中介收取中介费

对这个模型进行分析

  • 抽象角色:一目了然,房主和中介都要租房,因此出租房子是抽象角色(用的是抽象接口)
  • 真实角色:房东,是真实被代理的角色,租房是被代理的权利
  • 代理角色:中介,中介除了做抽象角色租房子外,还有签合同等附属操作
  • 客户:访问代理对象

该模型好处的分析

  • 业务分离,中介办理里租房的大部分事情,房主只需要出租房屋
  • 房主的操作更加纯粹
  • 如果中介还要进行其他的服务,容易管理

动态代理模式

动态代理模式继承了静态代理模式的所有优点以及他的代理角色。

但是不同点是:动态代理的代理对象是动态生成的,并且代码十分简短

一般简短的代码在理解起来都很难

对于动态代理,需要了解两个类Proxy类InvocationHander类

这两个类是动态代理的核心,动态代理的绝大多是代码都是固定死的,只要输入参数通过反射机制获取参数,动态创建对象。

InvocationHander类

这个类是实例化调用的处理程序实现的接口

这个类只用一个invoke(proxy,args)方法,这个方法不用我们手动执行,在这个类被加载的时候就默认执行了。

Proxy类

Proxy类提供了创建的动态代理类和实例的静态方法


还是通过这个租房模型,通过动态代理来实现

动态代理类的组成

  • 抽象代理对象:一个抽象接口
  • 创建一个动态代理类继承实现InvocationHandler对象
  • 在这个类中设置我们的rent
  • 在这个类中获得Proxy

完整的动态代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.dwx.test02;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class InvocationHanderProxy implements InvocationHandler {
//对于代理角色 需要抽象对象
private Rent rent;

//设置抽象接口
public void setRent(Rent rent) {
this.rent = rent;
}

//对于动态代理需要获得Proxy
public Object getProxy(){
//这里也是固定的 底层原理是反射
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这里只需要两个参数:args(不变)和rent(我们的抽象类)
return method.invoke(rent, args);
}
}

此时的测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.dwx.test02;

public class test {
public static void main(String[] args) {
//现在动态代理类以及全部创建结束
//对于动态代理 需要代理对象
Host dwx = new Host("dwx");
//但是动态代理暂时没有代理对象 需要创建
InvocationHanderProxy ip = new InvocationHanderProxy();
ip.setRent(dwx);
Rent proxy = (Rent) ip.getProxy();
//此时的动态代理对象就生成了
proxy.rent();
}
}

这几步也是固定的不用更改;

Spring使用注解开发

Spring使用注解开发

Spring完全可以脱离项目里,而使用注解进行开发。

这里我们主要了解Spring对<bean>的替代。

在前面的学习过程中,<bean>可以对java程序的每一曾都有管理,因此使用注解也可以对程序的每一层进行管理。

使用注解开发的要点

使用注解进行开发必须注意,一定要在xml文件中配置允许注解的配置,一定要开启注解,一定要将需要使用注解的类的包进行扫描

xml依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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"
>



</beans>

开起注解:

<context:annotation-config/>

对包进行扫描:

<context:component-scan base-package="包名"/>

注解对各层的托管

这里我们创建一个有多个层的环境进行测试:

  • Dao层
  • Pojo层
  • Service层
  • Controller层

对婆婆层的托管

对pojo层托管使用注解@Component

这样pojo层就被注册成功了,而他的id默认是该类名的小写

test

1
2
3
4
5
6
7
8
9
10
11
12
import com.dwx.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTset {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContest.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
}
}

如何给属性赋值(注入)?

对属性进行注入可以再该属性的上边或者在该属性的set方法上加上@Value("")来进行赋值

pojo层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.dwx.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class User {
@Value("dwx")
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}

结果:

1
User{name='dwx'}

对Dao层的托管

使用@Repository

dao层

1
2
3
4
5
6
7
8
9
package com.dwx.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

}

对Service层的托管

使用@Service

service层

1
2
3
4
5
6
7
8
package com.dwx.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
}

对Controller层的托管

使用@Controller

controller层

1
2
3
4
5
6
7
8
9
package com.dwx.controller;


import org.springframework.stereotype.Controller;

@Controller
public class UserController {
}

有趣的点

有趣的是,其实这些层的注解的功能都是一样的。但是为了分层,给他们了名字不同的注解,但是这些注解的实际功能都是一样的。

  • Copyrights © 2015-2023 dwx
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信