spring笔记

Spring入门

POM依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

Bean定义文件/resource/spring-context.xml:

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userDAO" class="com.qf.dao.UserDAOImpl" scope="singleton" lazy-init="false" init-method="init" destroy-method="destroy"/>
    <bean id="userService" class="com.qf.service.UserServiceImpl" autowire="byName">
        <property name="userDAO" ref="userDAO"/>
    </bean>
</beans>

编写对应的java类;

开始使用:

//获取context
ApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
//获取bean
UserService userService = (UserService) context.getBean("userService");

spring-ioc-xml方式

Bean实例化三种方式

无参构造方法实例化(id,class)
工厂静态方法实例化(id,class,factory-method)
工厂实例方法实例化(id,factory-bean,factory-method)

Bean的作用范围

scope属性:singleton(默认值)和prototype

singleton:单例模式,默认饿汉模式

prototype:非单例模式,默认懒汉模式

Bean的生命周期方法

init-method
destroy-method

依赖注入

1、set方法注入:

<bean id="userDAO" class="com.qf.dao.UserDAOImpl"/>
<bean id="userService" class="com.qf.service.UserServiceImpl">
    <property name="userDAO" ref="userDAO"/>
</bean>

UserServiceImpl类中含有字段userDAO,和对应setter方法。

2、构造方法注入

<bean id="student" class="com.qf.entity.Student">
    <constructor-arg name="id" value="1"/>
    <constructor-arg name="name" value="小明"/>
</bean>

构造方法入参需要按顺序写,name并不是入参名,它可以随便写。

3、自动注入

<!--no方式,默认值,即不使用自动注入-->

<!--byName方式,需要UserServiceImpl类中有个字段叫userDAO-->
<bean id="userDAO" class="com.qf.dao.UserDAOImpl"/>
<bean id="userService" class="com.qf.service.UserServiceImpl" autowire="byName"/>

<!--byType方式,spring容器会找到符合类型的bean赋给字段,如果找到多个bean则报错-->
<bean id="aaa" class="com.qf.dao.UserDAOImpl"/>
<bean id="userService" class="com.qf.service.UserServiceImpl" autowire="byType"/>

<!--constructor方式,构造方法的byType方式,会自动注入构造入参,必须要能找到唯一一个符合的bean-->
<bean id="aaa" class="com.qf.dao.UserDAOImpl"/>
<bean id="userService" class="com.qf.service.UserServiceImpl" autowire="constructor"/>

注入数据的类型

1、普通数据类型

2、引用数据类型

3、集合数据类型

<bean id="user" class="com.qf.entity.User">
    <!--int-->
    <property name="id" value="1"/>
    
    <!--String-->
    <property name="name" value="张灿"/>
    
    <!--Date,要按格式写-->
    <property name="bornDate" value="1993/10/1 1:2:3"/>
    
    <!--String[]-->
    <property name="hobbys">
        <array>
            <value>football</value>
            <value>basketball</value>
        </array>
    </property>
    
    <!--List-->
    <property name="names">
        <list>
            <value>tom</value>
            <value>jack</value>
        </list>
    </property>
    
    <!--Set-->
    <property name="phones">
        <set>
            <value>11122223333</value>
            <value>11122223333</value>
        </set>
    </property>
    
    <!--Map-->
    <property name="countries">
        <map>
            <entry key="zh" value="china"/>
            <entry key="en" value="english"/>
        </map>
    </property>
    
    <!--Properties-->
    <property name="files">
        <props>
            <prop key="url">jdbc:mysql:xxx</prop>
            <prop key="username">root</prop>
        </props>
    </property>
    
    <!--引用数据-->
    <property name="address" ref="addr"/>
</bean>

<!--被引用的bean-->
<bean id="addr" class="com.qf.entity.Address">
    <property name="id" value="1"/>
    <property name="city" value="bj"/>
</bean>

引入其他配置文件

<import resource="other.xml"/>

spring-ioc-annotation方式

spring原始注解

@Component,使用在类上用于实例化Bean
@Controller,同@Component,表明用于web层
@Service,同@Component,表明用于service层
@Repository,同@Component,表明用于dao层
@Autowired,使用在字段上用于根据类型依赖注入
@Qualifier,结合@Autowired一起使用用于根据名称进行注入
@Resource,相当于@Autowired+@Qualifier
@Value,注入普通属性
@Scope,标注Bean的作用范围
@PostConstructor,标注Bean的初始化方法
@PreDestroy,标注Bean的销毁方法

spring新注解

@Configuration,用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解
@ComponentScan,用于指定spring在初始化容器时要扫描的包
@Bean,使用在方法上,标注将该方法的返回值存储到spring容器中
@PropertySource,用于加载properties文件中的配置
@Import,用于导入其他配置类

示例代码

编写配置类:

@Configuration
@ComponentScan("com.qf")
@PropertySource("classpath:jdbc.properties")
@Import(SubConfiguration.class)
public class SpringConfiguration {
    @Bean("userDAO")
    @Scope("singleton")
    public UserDAO getUserDAO() {
        return new UserDAO() {
            @Override
            public void deleteUser(int id) {
                System.out.println("xxx");
            }
        };
    }
}

其他Bean类:

@Service("userService")
public class UserServiceImpl implements UserService {
    @Value("${jdbc.driver}")
    private String name;

    @Autowired
    @Qualifier("userDAO")
    private UserDAO userDAO;
    ...
}

使用:

// 获取context
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
// 获取bean
UserDAO userDAO = (UserDAO) context.getBean("userDAO");

spring集成junit

为什么要集成?

传统的junit测试方法中,需要手动创建spring容器和获取bean,如下:

ApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml");
UserService userService = (UserService) context.getBean("userService");

spring集成junit步骤

(1)导入spring集成junit的依赖

(2)使用@Runwith注解替换原来的运行时

(3)使用@ContextConfiguration指定配置文件或配置类

(4)使用@Autowired注入需要测试的对象

(5)创建测试方法进行测试

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>6.0.9</version>
</dependency>
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration("classpath:spring-anno-ctx.xml")
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
    @Autowired
    private UserService userService;

    @Test
    public void test1() {
        userService.deleteUser(1);
    }
}

JavaWeb入门

简单示例

(1)新建java ee工程

(2)自动引入依赖:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>

(3)创建一个Servlet:

package com.example.tomcattest;

import java.io.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet extends HttpServlet {
    private String message;

    public void init() {
        message = "Hello World! servlet中文12";
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");

        // Hello
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>");
    }

    public void destroy() {
    }
}

(4)上面servlet使用了注解方式,如果不用注解,则需要在webapp/WEB-INFO/web.xml中指定映射关系:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.example.tomcattest.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello-servlet</url-pattern>
    </servlet-mapping>
</web-app>

web容器监听器

每次在servlet方法中创建spring context不仅繁琐,而且增加内存消耗。

我们可以在web容器启动时,先创建好spring context,后面使用时直接获取。

(1)创建一个ServletContextListener,并添加注解:

@WebListener
public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        sce.getServletContext().setAttribute("ctx", context);
        System.out.println("ContextLoaderListener set ctx success.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

(2)在servlet中获取:

ServletContext servletContext = request.getServletContext();
ApplicationContext context = (ApplicationContext) servletContext.getAttribute("ctx");
UserService userService = (UserService) context.getBean("userService");

SpringMVC

SpringMVC的开发步骤

1、导入SpringMVC包

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.0.9</version>
</dependency>

2、配置Servlet(共有行为,web.xml文件)

<!--配置SpringMVC前端控制器-->
<servlet>
    <servlet-name>DispatherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>DispatherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3、编写Controller(特有行为)

4、将Controller使用注解配置到Spring容器中

@Controller()
public class UserController {
    @RequestMapping("/quick")
    public String save() {
        System.out.println("UserController.save...");
        return "success.jsp";
    }
}

5、创建SpringMVC核心配置文件(spring-mvc.xml文件)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns: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/beans/spring-context.xsd">

    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.example.tomcattest.controller"/>

</beans>

6、执行访问测试

SpringMVC的执行流程

1、用户请求至DispatcherServlet前端控制器

2、DispatcherServlet调用HandlerMapping处理器映射器

3、HandlerMapping找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet

4、DispatcherServlet调用HandlerAdapter处理器适配器

5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、Controller执行完成返回ModelAndView

7、HandlerAdapterModelAndView返回给DispatcherServlet

8、DispatcherServletModelAndView传给ViewResolver视图解析器

9、ViewResolver解析后返回具体View

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、DispatcherServlet响应用户。

SpringMVC的XML配置解析

1、视图解析器

SpringMVC有默认组件配置,在org/springframework/web/servlet/DispatcherServlet.properties文件中。

spring-web.xml举例:

<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

SpringMVC的数据响应

1.1 数据响应方式

1、页面跳转(直接返回字符串、通过ModelAndView对象返回)

2、回写数据(直接返回字符串、返回对象或集合)

1.2 页面跳转

1、返回字符串形式:此种方式会将返回的字符串与视图解析器的前后缀拼接后进行跳转。

resource/spring-mvc.xml中配置内部资源视图解析器:

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

编写Controller:

@RequestMapping("/save")
public String save() {
    return "success";
}

表示渲染/webapp/jsp/success.jsp页面。

还可以返回带有前缀的字符串(不受前后缀影响):

转发:forward:save表示交由save()方法处理。forward:/jsp/success.jsp表示直接渲染该jsp页面。

重定向:redirect:save表示交由save()方法处理且浏览器地址变为ip:port/saveredirect:/jsp/success.jsp表示直接渲染该jsp页面。

2、返回ModelAndView对象

基本用法:

@RequestMapping("model")
public ModelAndView model() {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("username", "张灿");//jsp中可以使用${username}
    modelAndView.setViewName("success");
    return modelAndView;
}

ModelAndView也可以注入:

@RequestMapping("model")
public ModelAndView model(ModelAndView modelAndView) {
    modelAndView.addObject("username", "张灿");
    modelAndView.setViewName("success");
    return modelAndView;
}

可以只注入Model来设置数据,返回视图文件名:

@RequestMapping("model2")
public String model2(Model model) {
    model.addAttribute("username", "model2");
    return "success";
}

也可以注入传统的HttpServletRequest:

@RequestMapping("model3")
public String model3(HttpServletRequest request) {
    request.setAttribute("username", "model3");
    return "success";
}
1.3 回写数据

1、直接返回字符串

使用jave web的方式:

@RequestMapping("data")
public void data(HttpServletResponse response) throws IOException {
    response.getWriter().print("data");
}

使用SpringMVC的方式:

@RequestMapping("data2")
@ResponseBody //告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回
public String data2() {
    return "data2";
}

返回json字符串:

(1)pom.xml添加依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.15.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.15.0</version>
</dependency>

(2)编写User类(注意要有get方法)

public class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }
}

(3)编写Controller类的方法

@RequestMapping("data3")
@ResponseBody
public String data3() throws JsonProcessingException {
    User user = new User("zc", 30);
    //使用jackson将对象转换成json格式字符串
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(user);
    return json;
}

2、返回对象或集合(需要导入上面的jackson)

先修改/resources/spring-mvc.xml文件:

<!--配置处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </list>
    </property>
</bean>

再编写Controller类的方法:

@RequestMapping("data4")
@ResponseBody
//期望SpringMVC自动将User转换成json格式字符串
public User data4() {
    return new User("data4", 30);
}

上面配置spring-mvc.xml比较麻烦,我们可以使用mvc的注解驱动代替上述配置:

(记得要引入mvc的命名空间)
(把上面的 配置处理器映射器 注释掉)
<!--mvc的注解驱动-->
<mvc:annotation-driven/>

原理:在SpringMVC的各个组件中,处理器映射器处理器适配器视图解析器 称为三大组件。

使用<mvc:annotation-driven/>会自动加载RequestMappingHandlerMapping(处理器映射器)RequestMappingHandlerAdapter(处理器适配器),可在spring-mvc.xml配置文件中替代注解处理器和适配器的配置。

同时默认底层就会集成jackson进行对象或集合的json格式字符串的转换。

SpringMVC的请求

1.1 获得请求参数

1、请求参数类型

基本类型参数

POJO类型参数

数组类型参数

集合类型参数

1.2 获得基本类型参数

@RequestMapping("request")
@ResponseBody
public String request(String name, int age) {
    return "name = " + name + ", age = " + age;
}

1.3 获得POJO类型参数

private static class Dog {
    private String name;
    private int age;

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

    public void setAge(int age) {
        this.age = age;
    }

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

@RequestMapping("request2")
@ResponseBody
public String request2(Dog dog) {
    return dog.toString();
}

//发送请求:/api/request2?name=abc&age=11

1.4 获得数组类型参数

@RequestMapping("request3")
@ResponseBody
public String request3(String[] strs) {
    return Arrays.toString(strs);
}

//发送请求:/api/request3?strs=a&strs=b

1.5 获得集合类型参数——封装POJO方式

准备一个jsp页面来发送表单:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Form</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/request4" method="post">
        <input type="text" name="dogList[0].name"><br/>
        <input type="text" name="dogList[0].age"><br/>
        <input type="text" name="dogList[1].name"><br/>
        <input type="text" name="dogList[1].age"><br/>
        <input type="submit" value="提交">
    </form>
</body>
</html>

处理请求:

private static class VO {
    private List<Dog> dogList;

    public List<Dog> getDogList() {
        return dogList;
    }

    public void setDogList(List<Dog> dogList) {
        this.dogList = dogList;
    }

    @Override
    public String toString() {
        return "VO{" +
                "dogList=" + dogList +
                '}';
    }
}

@RequestMapping("request4")
@ResponseBody
public String request4(VO vo) {
    return vo.toString();
}

1.6 获得集合类型参数——直接接收数据

处理请求:

@RequestMapping("request5")
@ResponseBody
//要给入参加上@RequestBody注解
public String request5(@RequestBody List<Dog> dogList) {
    return dogList.toString();
}

发送请求:要表示json类型

POST http://localhost:8080/tomcat_test_war_exploded/request5
Content-Type: application/json;charset=utf-8

[
{"name":"a","age":1},
{"name":"b","age":2}
]

1.7 静态资源访问的开启

静态资源是路径形式的,RequestMapping映射不出来,可以这样解决:

<!--方法1:指定静态资源不走RequestMapping映射-->
<mvc:resources mapping="/static/**" location="/static/"/>
<!--方法2:如果RequestMapping映射失败,交由原始容器处理-->
<mvc:default-servlet-handler/>

1.8 配置全局乱码过滤器

在web.xml,修改读取输入参数时的编码:

<!--配置全局过滤的filter-->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

在spring-mvc.xml,修改输出时的编码:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

1.9 参数绑定注解@requestParam

@RequestMapping("request6")
@ResponseBody
public String request6(@RequestParam(value = "name", required = false, defaultValue = "def") String username) {
    return username;
}

1.10 获得RESTful风格的参数

@RequestMapping(value = "request7/{name}", method = RequestMethod.GET)
@ResponseBody
public String request7(@PathVariable(value = "name", required = false) String username) {
    return "用户" + username;
}

1.11 自定义类型转换器

自定义转换器类实现Converter接口:

public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

在spring-mvc.xml中声明转换器:

<!--声明转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.example.tomcattest.converter.DateConverter"/>
        </set>
    </property>
</bean>

spring-mvc.xml在<annotation-driven>中引用转换器:

<mvc:annotation-driven conversion-service="conversionService"/>

1.12 获得Servlet相关API

直接注入就行:

@RequestMapping("request9")
@ResponseBody
public void request9(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    System.out.println(request);
    System.out.println(response);
    System.out.println(session);
}

1.13 获得请求头

(1)使用@RequestHeader

@RequestMapping("request10")
@ResponseBody
public String request10(@RequestHeader(value = "User-Agent", required = false) String userAgent) {
    return userAgent;
}

(2)特殊的头@CookieValue

@RequestMapping("request11")
@ResponseBody
public String request11(@CookieValue("JSESSIONID") String jsessionID) {
    return jsessionID;
}
1.2 文件上传

1.1 客户端表单实现

(1)导入fileupload和io坐标(实际使用不写也没事)

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.2</version>
</dependency>

(2)sping-mvc配置文件上传解析器

bean id是固定的,不能随便写,不然会不生效。

<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="500000000"/>
    <property name="defaultEncoding" value="utf-8"/>
</bean>

(3)编写处理代码

@RequestMapping("upload")
@ResponseBody
public String upload(String name, MultipartFile uploadFile) {
    return name + ", " + uploadFile.getOriginalFilename();
}

发送请求:

POST /tomcat_test_war_exploded/upload HTTP/1.1
Host: localhost:8080
Content-Length: 294
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="uploadFile"; filename="/C:/Users/张灿/Pictures/高性能.png"
Content-Type: image/png

(data)
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="name"

张灿
------WebKitFormBoundary7MA4YWxkTrZu0gW--

如果上传多个同名的文件,则在服务端用MultipartFile[]接收。

SpringMVC的拦截器

1.1 拦截器的作用

对处理器进行预处理和后处理。

1.2 拦截器快速入门

①创建拦截器类实现HandlerInterceptor接口

public class MyInterceptor1 implements HandlerInterceptor {
    //在目标方法执行之前,执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String s = String.format("MyInterceptor1.preHandle: request_path={%s}", request.getPathInfo());
        System.out.println(s);
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    //在目标方法执行之后、视图对象返回之前,执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        String s = String.format("MyInterceptor1.postHandle: response_status={%d}", response.getStatus());
        System.out.println(s);
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    //在流程都执行完毕后,执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1.afterCompletion");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

②配置拦截器

spring-mvc.xml:

<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/login"/>
        <bean class="com.example.spring_test.interceptor.MyInterceptor1"/>
    </mvc:interceptor>
</mvc:interceptors>

③测试

访问http://localhost:8080/spring_test_war_exploded/test/test1

查看打印:

MyInterceptor1.preHandle: request_path={/test/test1}
TestController.test1
MyInterceptor1.postHandle: response_status={200}
MyInterceptor1.afterCompletion
login拦截器示例

拦截器类:

public class PrivilegeInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
//            response.sendError(401, "未登录");
            request.getRequestDispatcher("/login/unlogined").forward(request, response);
            return false;
        }
        return true;
    }
}

spring-mvc配置拦截器:

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/**"/>
            <mvc:exclude-mapping path="/login/**"/>
            <bean class="com.example.spring_test.interceptor.PrivilegeInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

login请求的操作:

@Controller
@RequestMapping("login")
public class LoginController {
    @Autowired
    private UserService userService;

    @PostMapping
    @ResponseBody
    public String login(@RequestBody User user, HttpSession session) {
        User user1 = userService.login(user.getUsername(), user.getPassword());
        if (user1 != null) {
            session.setAttribute("user", user1);
            return "登录成功";
        }
        return "登录失败";
    }

    @RequestMapping("unlogined")
    @ResponseBody
    public String unLogined() {
        return "未登录";
    }
}

SpringMVC的异常处理

1.1 异常处理的两种方式

(1)使用框架提供的简单异常处理器SimpleMappingExceptionResolver

(2)使用自定义异常处理器,实现HandlerExceptionResolver

1.2 简单异常处理器

在spring-mvc.xml配置:

<!--配置异常处理器-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="defaultErrorView" value="error"/>
    <property name="exceptionMappings">
        <map>
            <entry key="com.example.spring_test.exception.MyException1" value="error1"/>
        </map>
    </property>
</bean>
1.3 自定义异常处理器

(1)编写异常处理类:

public class MyExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView();

        if (ex instanceof MyException1) {
            modelAndView.addObject("info", "自定义异常");
        }

        modelAndView.setViewName("error");

        return modelAndView;
    }
}

(2)配置spring-mvc.xml:

<bean class="com.example.spring_test.exception.MyExceptionResolver"/>

tomcat控制台中文乱码问题

tomcat启动控制台和system.out.println输出中文乱码问题 - 癫狂编程 - 博客园 (cnblogs.com)

Spring JdbcTemplate

1、开发步骤

导入spring-jdbc和spring-tx

创建数据库表和实体

创建JdbcTemplate对象

执行数据库操作

2、入门代码

(1)导入依赖:

mysql-connector-java、c3p0、spring-jdbc

(2)在mysql中创建数据表

(3)代码

//创建数据源对象
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/sql_test");
dataSource.setUser("root");
dataSource.setPassword("toor");

//创建JdbcTemplate
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);

//执行更新操作
int rows =jdbcTemplate.update("insert into account value(?,?)", "zc1", "1.1");
System.out.println("更新行数:" + rows);

3、Spring产生JdbcTemplate

就用spring的ioc实现,这里以xml方式方式举例。

(1)编写spring配置文件/resource/spring-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

    <!--加载jdbc.properties-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--数据源对象-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--jdbc模板对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

(2)上面引用的属性文件/resource/jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sql_test
jdbc.username=root
jdbc.password=toor

(3)使用:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
int rows =jdbcTemplate.update("insert into account value(?,?)", "zc2", "1.2");
System.out.println("更新行数:" + rows);

4、常用操作

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class JdbcTemplateCRUDTest {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Test
    public void testUpdate() {
        jdbcTemplate.update("update account set money=? where name=?", 10, "zc1");
    }

    @Test
    public void testDelete() {
        jdbcTemplate.update("delete from account where name=?", "zc1");
    }

    @Test
    public void testQueryAll() {
        List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<>(Account.class));
        System.out.println(accountList);
    }

    @Test
    public void testQueryOne() {
        Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<>(Account.class), "zc2");
        System.out.println(account);
    }

    @Test
    public void testQueryCount() {
        Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
        System.out.println(count);
    }
}

Spring AOP

AOP,面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

实现原理:基于jdk的动态代理、基于cglib的动态代理。

基于jdk的动态代理

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

        //增强对象
        Advice advice = new Advice();

        //handler
        InvocationHandler handler = new InvocationHandler() {
            //调用代理对象的任何方法,都会走进这里
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                advice.before();
                Object ret = method.invoke(target, args);
                advice.after();
                return ret;
            }
        };

        //代理对象
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
                TargetInterface.class.getClassLoader(),//目标对象类加载器
                new Class<?>[]{TargetInterface.class},//目标对象实现的接口
                handler
        );

        proxy.save();
    }
}

基于cglib的动态代理

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

        //增强对象
        Advice advice = new Advice();

        //基于cglib生成代理对象
        //1、创建增强器
        Enhancer enhancer = new Enhancer();
        //2、设置父类
        enhancer.setSuperclass(Target.class);
        //3、设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                advice.before();
                Object ret = method.invoke(target, args);
                advice.after();
                return ret;
            }
        });
        //4、创建代理对象
        Target proxy = (Target) enhancer.create();

        proxy.save();
    }
}

AOP相关概念

Target(目标对象):代理的目标对象

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

Joinpoint(连接点):那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点

Pointcut(切入点):要对哪些Joinpoint进行拦截

Advice(通知/增强):拦截到Joinpoint之后要做的事情

Aspect(切面):切入点和通知的结合

Waeving(织入):把增强应用到目标对象来创建新的代理对象的过程。Spring采用动态代理织入,而AspectJ采用编译期织入和类加载织入

基于xml的AOP开发

入门代码

①导入AOP相关坐标

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.19</version>
</dependency>

②创建目标接口和目标类(内部有切点)

public interface TargetInterface {
    void save();
}

public class Target implements TargetInterface {
    @Override
    public void save() {
        System.out.println("Target.save");
    }
}

③创建切面类(内部有增强方法)

public class MyAspect {
    public void before() {
        System.out.println("前置增强...");
    }
}

④将目标类和切面类的对象创建权交给spring

<!--目标对象-->
<bean id="target" class="com.qf.proxy.aop.Target"/>

<!--切面对象-->
<bean id="myAspect" class="com.qf.proxy.aop.MyAspect"/>

⑤在spring-context.xml中配置织入关系

<!--配置织入:哪些方法需要进行哪些增强-->
<aop:config>
    <!--声明切面-->
    <aop:aspect ref="myAspect">
        <!--切点+通知-->
        <aop:before method="before" pointcut="execution(public void com.qf.proxy.aop.Target.save())"/>
    </aop:aspect>
</aop:config>

⑥测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class AopTest {
    @Autowired
    private TargetInterface target;

    @Test
    public void test1() {
        target.save();
    }
}
切点表达式的写法
execute([修饰符] 返回值 包名.类名.方法名(参数))

举例:

execute(public void com.zc.Target.method(String,int)) //具体某个方法
execute(void com.zc.Target.*(..)) //Target类下的所有返回值为void的方法
execute(* com.zc.*.*(..)) //com.zc包下的所有类的方法
execute(* com.zc..*.*(..)) //com.zc包及其子包下的所有类的方法
execute(* *..*.*(..)) //所有方法
通知的种类
<aop:before>:前置通知
<aop:after-returning>:后置通知
<aop:around>:环绕通知,即前置+后置都执行
<aop:after-throwing>:异常抛出通知,即出现异常时执行
<aop:after>:最终通知,即无论是否有异常都会执行

其中,around的增强方法比较特殊,需要这样定义:

public Object around(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("环绕前增强...");
    Object ret = pjp.proceed();
    System.out.println("环绕后增强...");
    return ret;
}
切点表达式的抽取

前面的切点表达式很多是重复的,我们可以把切点表达式抽取出来,然后引用它:

<!--配置织入:哪些方法需要进行哪些增强-->
<aop:config>
    <!--抽取切点表达式-->
    <aop:pointcut id="aopPointcut" expression="execution(* com.qf.proxy.aop.Target.*(..))"/>
    <!--声明切面-->
    <aop:aspect ref="myAspect">
        <!--切点+通知-->
        <aop:before method="before" pointcut-ref="aopPointcut"/>
        <aop:after-returning method="afterReturning" pointcut-ref="aopPointcut"/>
        <aop:after-throwing method="afterThrowing" pointcut-ref="aopPointcut"/>
        <aop:after method="after" pointcut-ref="aopPointcut"/>
    </aop:aspect>
</aop:config>

基于注解的AOP开发

入门代码

①创建目标接口和目标类(内部有切点)

public interface TargetInterface {
    void save();
}

@Component("target1")
public class Target implements TargetInterface {
    @Override
    public void save() {
        System.out.println("Target.save");
    }
}

②创建切面类(内部有增强方法)

@Component("myAspect")
@Aspect
public class MyAspect {
    @Before("execution(* com.qf.proxy.anno.Target.*(..))")
    public void before() {
        System.out.println("前置增强...");
    }

    //引用切点表达式
    @AfterReturning("pointcut()")
    public void afterReturning() {
        System.out.println("后置增强...");
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前增强...");
        Object ret = pjp.proceed();
        System.out.println("环绕后增强...");
        return ret;
    }

    @AfterThrowing("MyAspect.pointcut()")
    public void afterThrowing() {
        System.out.println("抛出异常后增强...");
    }

    @After("pointcut()")
    public void after() {
        System.out.println("最终增强...");
    }

    //切点表达式的抽取
    @Pointcut("execution(* com.qf.proxy.anno.Target.*(..))")
    private void pointcut() {
    }
}

③将目标类和切面类的对象创建权交给spring

④在切面类中使用注解配置织入关系

见步骤2

⑤在配置文件中开启组件扫描和AOP自动代理

@Configuration
@ComponentScan("com.qf.proxy.anno")
@EnableAspectJAutoProxy
public class MyAppConfiguration {}

⑥测试

声明式事务控制

编程式事务控制相关对象

PlatformTransactionManager接口是spring的事务管理器。

TransactionDefinition是事务的定义信息对象。

TransactionStatus是事务具体的运行状态。

基于xml的声明式事务控制

<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--通知:事务的增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!--配置事务的aop织入-->
<aop:config>
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.zc.service.impl.*.*(..))"/>
</aop:config>

基于注解的声明式事务控制

平台事务管理器配置(xml方式)

<!--配置平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

事务通知的配置(注解配置),写在业务类中

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public void transfer(String outMan, String inMan, double money) {
        accountDao.out(outMan, money);
        int a = 1/0;
        accountDao.in(inMan, money);
    }
}

事务注解驱动的配置(xml方式)

<tx:annotation-driven transaction-manager="transactionManager"/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 数组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 数组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:数组的长度是固定的,不适合存储大小不固定的动态数据,另外数组在内存中是连续分配的,当数组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值