川职院-课堂笔记(2)5-27日起

每日笔记整理:

2022-05-27

过滤器

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。
使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
总之过滤器实际上就是对所有请求进行过滤操作,获取请求携带的数据或者修改请求的某些参数。

Spring-字符编码过滤器配置

<!-- 字符编码过滤器 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <!-- 定义编解码的字符集 -->
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <!-- 定义是否使用强制字符集(设置为true代表请求和响应都必须要转换字符集) -->
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

自定义过滤器

(1)创建一个自定义过滤器类,实现Filter接口

package com.huawei.sys.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * 测试过滤器类
 * 2022/5/27
 */
public class MyFilter implements Filter {

    /**
     * init 方法
     * 过滤器初始化的回调方法
     * 当容器初始化,过滤器也初始化,且只会初始化一次
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter-初始化!");
    }

    /**
     * doFilter 方法,拦截到请求后会执行的方法(每次请求一旦被拦截都会被调用)
     * @param servletRequest 网络io请求流
     * @param servletResponse 网络io响应流
     * @param filterChain filterChain.doFilter();//让过滤器通过拦截,放行请求
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("过滤器被调用!");

        filterChain.doFilter(servletRequest,servletResponse);//放行请求
        
    }

    /**
     * destroy 过滤器销毁的回调
     * 当容器销毁,过滤器就随之销毁
     */
    @Override
    public void destroy() {
        System.out.println("过滤器-销毁!");
    }
}

demo:拦截请求返回html代码

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("过滤器被调用!");

        PrintWriter writer = servletResponse.getWriter();

        servletResponse.setCharacterEncoding("UTF-8");
        String html = "<html>" +
                "<head>" +
                "<meta charset='UTF-8' /></head>" +
                "<body>" +
                "请求被过滤器阻止!</body></html>";

        writer.println(html);

        //filterChain.doFilter(servletRequest,servletResponse);//放行请求

    }

(2)在web.xml文件中配置过滤器

<!-- 自定义配置过滤器 -->
  <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.huawei.sys.filter.MyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/user/*</url-pattern>
  </filter-mapping>

SpringMVC拦截器

是基于Java的jdk动态代实现的,实现HandlerInterceptor接口。不依赖于servlet容器,拦截器针对于contraller方法,并且能获取到所有的类,对类里面所有的方法实现拦截,粒度更小,拦截器中>可以注入service,也可以调用业务逻辑。

自定义拦截器方法

(1)定义一个类实现HandlerInterceptor接口

package com.huawei.sys.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * 自定义拦截器
 * 2022/5/27
 */
public class MyInterceptor implements HandlerInterceptor {

    /**
     * 在controller方法调用之前回调
     * @param request Http请求对象
     * @param response Http响应对象
     * @param handler 当前拦截器对象的实例
     * @return 需要返回一个布尔值:
     *              true  -》 拦截器放行
     *              false -》 拦截器阻止通行
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("1.在controller方法调用之前回调");

        return true;
    }

    /**
     * 在调用完成controller方法之后返回数据之前回调
     * @param request Http请求对象
     * @param response Http响应对象
     * @param handler 当前拦截器对象的实例
     * @param modelAndView 视图解析器需要接收的对象,可以定义要跳转的逻辑视图名以及包含要传送的数据
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("2.在调用完成controller方法之后返回数据之前回调");

        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);

    }

    /**
     * 当整个controller方法执行完成,且视图或者数据成功返回后回调
     * @param request Http请求对象
     * @param response Http响应对象
     * @param handler  当前拦截器对象的实例
     * @param ex 整个方法结束执行后可能没有成功会抛出异常,返回的异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("3.当整个controller方法执行完成,且视图或者数据成功返回后回调");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

(2)dispacther-servlet.xml配置文件中配置拦截器

<!-- 自定义拦截器配置 -->
    <!-- 拦截器定义标签 -->
    <mvc:interceptors>
        <!-- 拦截器的实例 -->
        <!-- 综合拦截器(所有的请求都会先进入当前拦截器) 一般不写 -->
<!--        <bean class="com.huawei.sys.interceptor.MyInterceptor" />-->
        <!-- 配置拦截器的拦截规则 <mvc:interceptor>可以配置多个,代表多个规则 -->
        <mvc:interceptor>
            <!-- 配置拦截的路径 -->
            <mvc:mapping path="/user/**" />
            <!-- 综合拦截器完成之后才会进入,下面的拦截器 -->
            <bean class="com.huawei.sys.interceptor.MyInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

2022-05-29

SpringMVC文件上传

(1)引入依赖

<!-- 文件上传下载-->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.4</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>

(2)在dispachter-servlet.xml配置文件中配置文件上传选项

<!-- 文件上传的配置 id值必须要叫multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
        <!-- 单次请求做大上传文件大小 -->
        <property name="maxUploadSize" value="5000000" />
        <!-- 文件字节码编解码方式 -->
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

(3)前端编写表单上传文件

<!-- 文件上传表单
 1.请求方法必须是post请求
 2.enctype属性multipart/form-data,代表有媒体元素上传
 -->
<form action="${pageContext.request.contextPath}/file/uploadOneFile" method="post" enctype="multipart/form-data">
    <!-- 文件上传的表单 -->
    <input type="file" name="uploadFile" />
    <!-- 其他字段:文件描述 autocomplete="false" 不会出现历史记录提示框-->
    <input type="text" autocomplete="false" name="descs" />
    <input type="submit" value="文件上传" />
</form>

(4)后端编写一个接收文件上传的pojo对象类

package com.huawei.sys.dto;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

/**
 * 用于接收上传文件的类
 * 2022/5/29
 */
@Data
public class FileDto {

    private MultipartFile uploadFile;//上传的文件对象
    
    private String descs;//文件描述字段

}

(5)编写Controller方法接收文件上传的请求

package com.huawei.sys.controller;

import com.huawei.sys.dto.FileDto;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 文件上传和下载操作类
 * 2022/5/29
 */

@Controller
@RequestMapping("/file")
public class FileController {

    @RequestMapping(value = "/uploadOneFile",method = RequestMethod.POST)
    @ResponseBody
    public Map<String,Object> uploadOneFile(FileDto file){

        //默认保存上传文件的服务器地址
        String savePath = "F://fileupload";

        //1.取得上传的文件对象
        MultipartFile uploadFile = file.getUploadFile();

        //2.获取文件的名称
        String originalFilename = uploadFile.getOriginalFilename();

        System.out.println("上传的文件名:"+originalFilename);

        //3.将文件保存到目标路径中(封装一个File文件对象)
        /**
         * new File(文件保存的文件位置,文件名称(一定要带后缀))
         */
        File saveFile = new File(savePath,originalFilename);

        //返回数据的Map对象
        Map<String,Object> resMap = new HashMap<>();

        //4.调用MulitpartFile对象的tansferTo方法进行文件上传
        try {
            uploadFile.transferTo(saveFile);

            resMap.put("code","0000");
            resMap.put("msg","文件上传成功!");
        } catch (IOException e) {
            System.err.println("文件上传出错!");
            resMap.put("code","9999");
            resMap.put("msg","文件上传失败!");
            e.printStackTrace();
        }

        return resMap;
    }

}

文件下载
(1)Servlet3.0的方法下载文件

 /**
     * 下载文件(单文件下载)
     * @param fileName 要下载的文件名称
     * @param response 响应对象
     * @return
     */
    @RequestMapping("/fileDownLoad")
    public String downLoadFile(String fileName, HttpServletResponse response) throws IOException {

        //服务器文件保存位置
        String savePath = "F://fileupload";

        //1.设置响应头的参数
        response.setHeader("Content-Type","application/x-msdownload");
        response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));

        //2.文件字节流读取文件
        String downLoadFilePath = savePath + "//"+fileName;//拼装出要下载的文件路径
        //获取文件字节输入流对象(服务中获取文件信息的io流)
        FileInputStream fileInputStream = new FileInputStream(downLoadFilePath);

        //3.通过响应对象获取输出流对象(服务器输出到客户端的io流)
        ServletOutputStream outputStream = response.getOutputStream();

        //4.通过io流输出文件
        //创建一个字节数组
        byte [] fileByte = new byte[fileInputStream.available()];

        fileInputStream.read(fileByte);//把读取的内容赋值到字节数组中

        //通过输出流输出
        outputStream.write(fileByte);

        //输出流
        outputStream.flush();
        outputStream.close();
        fileInputStream.close();

        return null;
    }

(2)SpringMVC的使用commons-io的下载方式

/**
     * SpringMVC文件下载
     * @param fileName 要下载的文件名称
     * @return
     */
    @RequestMapping("/filed2")
    public ResponseEntity<byte []> downloadFile2(String fileName) throws IOException {

        //服务器文件保存位置
        String savePath = "F://fileupload";

        //1.创建一个Http响应头对象
        HttpHeaders headers = new HttpHeaders();

        //2.创建文件对象(要下载的文件)
        File file = new File(savePath,fileName);

        //设置响应头的参数
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName,"UTF-8"));

        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
                headers, HttpStatus.CREATED);

    }

2022-05-30

Spring+SpringMVC搭建流程

(1)maven依赖整理

<?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>com.huawei</groupId>
  <artifactId>CZ_SpringMVCDemo1</artifactId>
  <version>1.0.0</version>
  <!-- tomcat运行的就是war包 -->
  <packaging>war</packaging>

  <name>CZ_SpringMVCDemo1 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>
    <!-- Spring版本号 -->
    <springBBH>5.2.3.RELEASE</springBBH>
  </properties>

  <dependencies>

    <!-- springMVC、Spring相关依赖 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${springBBH}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.3.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>
    <!--测试 @Test在方法上-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--日志 类上加上@Sl4j注解可以在类内部生成一个log对象-->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.21</version>
    </dependency>
    <!--J2EE  HttpServletRequest、XXXXXResponse-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!--mysql驱动包-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.22</version>
    </dependency>

    <!-- Fastjoson JSON处理工具 jackson  -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.78</version>
    </dependency>

    <!-- 文件上传下载-->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.4</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>

    <!-- 开发工具lombok:自动提供构造器、getter、setter方法等等注解 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.22</version>
      <scope>provided</scope>
    </dependency>

    <!-- @ResponesBody的新解决方案-jackson包 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.12.3</version>
    </dependency>
    <!-- 集成SpringMVC实现@ResponesBody注解的方法返回json数据 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.3</version>
    </dependency>

    <!-- 数据校验 -->
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>1.1.0.Final</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.logging</groupId>
      <artifactId>jboss-logging</artifactId>
      <version>3.1.0.CR2</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.1.0.Final</version>
    </dependency>


  </dependencies>

  <!-- maven工具构造配置 -->
  <build>
    <finalName>CZ_SpringMVCDemo1</finalName>

    <!-- maven静态资源打包 -->
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <!-- 指定路径下的指定后缀的文件也会进行打包 -->
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
          <include>**/*.js</include>
          <include>**/*.css</include>
          <include>**/*.html</include>
        </includes>
        <filtering>false</filtering>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
          <include>**/*.js</include>
          <include>**/*.css</include>
          <include>**/*.html</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>

    <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>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>8</source>
          <target>8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

(2)配置web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
  <!-- 项目名称 -->
  <display-name>Archetype Created Web Application</display-name>
  <!-- 容器初始化参数 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xml</param-value>
  </context-param>
  <!-- 容器加载监听器(加载配置文件时必须要写) -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- SpringMVC的前端控制器Servlet -->
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:dispatcher-servlet.xml</param-value>
    </init-param>

    <!-- 当容器加载时就加载当前servlet -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!-- 将请求的url地址映射对应的Servlet -->
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- HTTP请求REST的配置 如果拦截到delete、put请求就会把他们封装成post请求进行提交-->
  <filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- 字符编码过滤器 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <!-- 定义编解码的字符集 -->
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <!-- 定义是否使用强制字符集(设置为true代表请求和响应都必须要转换字符集) -->
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


</web-app>

(3)视图解析器配置文件必要配置项目

<?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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫描com.huawei路径下的所有被@Controller注解、@Component注解、@Service的类自动注册实例到ioc容器中国 -->
    <context:component-scan base-package="com.huawei" />

    <!-- 配置视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
    <!-- 静态资源文件夹目录配置 -->
    <mvc:annotation-driven />
    <mvc:resources location="/static/" mapping="/static/**" />

    <!-- 文件上传的配置 id值必须要叫multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
        <!-- 单次请求做大上传文件大小 -->
        <property name="maxUploadSize" value="5000000" />
        <!-- 文件字节码编解码方式 -->
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <!-- 推荐编写的一个格式化工具:字符串转日期 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <!-- 可以注册多个自定义的String转换器 -->
            <set>
                <bean class="com.huawei.sys.config.String2DateFormatter" />
            </set>
        </property>
    </bean>
</beans>

(4)包结构定义规则

父级:公司域名反写(com.huawei)

业务包名(sys)

控制器层(controller)

数据转换层(dto)

业务接口层(service)

业务接口实现层(impl)

​ 工具包(util)

​ 过滤器(filters)

​ 拦截器(interceptors)

​ 配置类(configs)

构建第一个MyBatis项目

(1)在resouces目录下创建一个mybatis配置文件

名称可以自定义

<?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="test">
        <environment id="test">
            <transactionManager type="JDBC"></transactionManager>    <!-- 事务管理类型:JDBC、MANAGED -->
            <dataSource type="POOLED">    <!-- 数据源类型:POOLED、UNPOOLED、JNDI -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/huawei?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC" />
                <property name="username" value="root" />
                <property name="password" value="root123456" />
            </dataSource>
        </environment>
    </environments>

    
</configuration>

(2)创建一个数据表

如:我创建一个学生表

CREATE TABLE `student`  (
  `code` varchar(20)  NOT NULL COMMENT '编号',
  `name` varchar(20)  COMMENT '姓名',
  `age` int(3)  COMMENT '年龄',
  PRIMARY KEY (`code`)
) ;

(3)创建一个与数据库字段相同的映射javaPOJO类

package com.huawei.dto;

import lombok.Data;

/**
 * 与数据库Student表实现映射的类
 * 2022/5/30
 */
@Data
public class StudentDo {

    private String code;

    private String name;

    private Integer age;

}

(4)在项目路径中创建一个dao包

dao包就是存放myBatis操作的代码

在dao包中创建接口,接口的目的就是解耦sql操作与业务操作之间的关系,命名规则为:业务+Mapper

/**
 * Mybatis映射接口层
 * 2022/5/30
 */
public interface StudentMapper {

    //根据学生编号查询学生数据
    StudentDo getStudentByCode(String code) throws IOException;

}

(5)编写映射xml文件

在项目目录下创建文件夹mybatis,将文件夹设置为资源文件路径

创建xml文件,命名规则为:业务名+Mapper.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">

<!-- 当前学习阶段 namespace值可自定义 -->
<mapper  namespace="StudentMapXML">

    <!-- 查询:根据学生编号查询学生数据 parameterType:代表的是参数类型 resultType:数据返回的类型-->
    <select id="getStudentByCode" parameterType="java.lang.String" resultType="com.huawei.dto.StudentDo">
        select * from student where code = #{code};
    </select>

</mapper>

#{} 是预编译处理,像传进来的数据会加个" "( #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号)
${} 就是字符串替换。直接替换掉占位符。$方式一般用于传入数据库对象,例如传入表名.
使用 ${} 的话会导致 sql 注入。所以为了防止 SQL 注入,能用 #{} 的不要去用 ${}
果非要用 ${} 的话,那要注意防止 SQL 注入问题,可以手动判定传入的变量,进行过滤,一般 SQL 注入会输入很长的一条 SQL 语句

(6)在mybatis配置文件中配置xml映射文件

<!-- 编写在configuration标签中 -->
<!-- 加载映射文件 mapper -->
    <mappers>
        <mapper resource="student/StudentMapper.xml" />
    </mappers>

(7)编写接口的实现类

package com.huawei.dao;

import com.huawei.dto.StudentDo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * mybatis自定义接口的实现类
 * 2022/5/30
 */
public class StudentMapperImpl implements StudentMapper{


    @Override
    public StudentDo getStudentByCode(String code) throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        //4.通过数据库连接对象调用mybatis映射文件中的sql方法
        StudentDo studentDo = sqlSession.selectOne("StudentMapXML.getStudentByCode", code);

        System.out.println(studentDo);

        //5.归还连接(关闭连接)
        sqlSession.close();

        return studentDo;
    }
}

入门版增删改查语句

(1)接口中方法定义

/**
 * Mybatis映射接口层
 * 2022/5/30
 */
public interface StudentMapper {

    //根据学生编号查询学生数据
    StudentDo getStudentByCode(String code) throws IOException;

    //查询出多行学生数据
    List<StudentDo> getStudentList() throws IOException;

    //新增学生信息(增、删、改-》返回的都是受影响的行数)
    int addStudent(StudentDo student) throws IOException ;

    //修改学生信息
    int updateStudent(StudentDo student) throws IOException ;

    //删除学生信息
    int deleteStudent(String code) throws IOException ;

}

(2)xml映射文件sql编写

<?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="StudentMapXML">

    <!-- 查询:根据学生编号查询学生数据 parameterType:代表的是参数类型 resultType:数据返回的类型-->
    <select id="getStudentByCode" parameterType="java.lang.String" resultType="com.huawei.dto.StudentDo">
        select * from student where code = #{code};
    </select>

    <!-- 查询所有学生信息(多行数据) -->
    <select id="getStudentList" resultType="com.huawei.dto.StudentDo">
        select * from student
    </select>

    <!-- 新增数据:添加学生信息 -->
    <insert id="addStudent" parameterType="com.huawei.dto.StudentDo" >
        INSERT into student VALUES(#{code},#{name},#{age})
    </insert>

    <!-- 修改数据:修改学生信息 -->
    <update id="updateStudent" parameterType="com.huawei.dto.StudentDo">
        update student set name=#{name},age=#{age} where code=#{code}
    </update>

    <!-- 删除数据:删除学生信息 -->
    <delete id="deleteStudent" parameterType="java.lang.String">
        delete from student where code = #{code}
    </delete>

</mapper>

(3)接口实现类实现方法

package com.huawei.dao;

import com.huawei.dto.StudentDo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * mybatis自定义接口的实现类
 * 2022/5/30
 */
public class StudentMapperImpl implements StudentMapper{


    @Override
    public StudentDo getStudentByCode(String code) throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        //4.通过数据库连接对象调用mybatis映射文件中的sql方法
        StudentDo studentDo = sqlSession.selectOne("StudentMapXML.getStudentByCode", code);

        System.out.println(studentDo);

        //5.归还连接(关闭连接)
        sqlSession.close();

        return studentDo;
    }

    @Override
    public List<StudentDo> getStudentList() throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        List<StudentDo> objects = sqlSession.selectList("StudentMapXML.getStudentList");

        for(StudentDo studentDo:objects){
            System.out.println(studentDo);
        }

        return objects;
    }

    @Override
    public int addStudent(StudentDo student) throws IOException  {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        int insert = sqlSession.insert("StudentMapXML.addStudent", student);

        System.out.println("新增【"+insert+"】行");

        sqlSession.commit();//提交事务

        return 0;
    }

    @Override
    public int updateStudent(StudentDo student)  throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        int update = sqlSession.update("StudentMapXML.updateStudent", student);

        System.out.println("修改【"+update+"】行");

        sqlSession.commit();//提交事务
        return 0;
    }

    @Override
    public int deleteStudent(String code)  throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        int delete = sqlSession.delete("StudentMapXML.deleteStudent", code);

        System.out.println("删除【"+delete+"】行");

        sqlSession.commit();//提交事务
        return 0;
    }
}

改写为sqlSession获取接口实现的实例

调用mybatis映射xml中的sql方法,改写为面向接口调用的方法

@Override
    public List<StudentDo> getStudentList() throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        //4.获取接口对象 !!!!!!!   重点改变的位置  !!!!!!!
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<StudentDo> studentList = mapper.getStudentList();

        return studentList;
    }

所以在这基础上,我们发现可以不用编写接口实现层,直接让mybatis完成实现调用

比如:在测试类中我们把接口实现层删掉,直接获取接口对象调用方法,它就会自动关联调用xml中的sql方法了

 @Test
    public void test1() throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        //通过接口字节码文件对象获取接口的实例
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<StudentDo> studentList = mapper.getStudentList();

        for(StudentDo studentDo:studentList){
            System.out.println(studentDo);
        }


    }

封装MyBatis获取连接的工具类

目的:减少创建工厂、获取连接的重复代码

package com.huawei.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * 获取mybatis数据连接的工具包
 * 2022/5/30
 */
public class SqlSessionUtil {

    //定义一个类常量:保证工厂类只有一个实例
    private final static SqlSessionFactory FACTORY;

    private SqlSessionUtil(){}

    //静态代码块
    static{

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = null;
        try {
            resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");
        } catch (IOException e) {
            System.err.println("MyBatis配置文件加载错误!");
            e.printStackTrace();
        }

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        FACTORY = new SqlSessionFactoryBuilder().build(resourceAsStream);

    }

    /**
     * 获取mybatis连接对象
     * @return sqlSession对象
     */
    public static SqlSession getSqlSession(){
        return FACTORY.openSession(true);
    }


}

测试:

@Test
    public void test1() throws IOException {

        //省略之前复杂的声明过程,直接调用工具类中的方法来获取即可
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();

        //通过接口字节码文件对象获取接口的实例
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<StudentDo> studentList = mapper.getStudentList();

        for(StudentDo studentDo:studentList){
            System.out.println(studentDo);
        }


    }

2022-05-31

mybatis核心配置文件

(1)properties配置标签

引入外部资源,注意顺序

<configuration>
    <!-- 引入外部配置文件 -->
    <properties resource="database.properties"></properties>
    ... ...

外部配置文件

#这个是mybatis的配置属性文件
#mysql驱动
driver=com.mysql.cj.jdbc.Driver
#mysql的服务器连接地址
url=jdbc:mysql://localhost:3306/huawei?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
#用户名
userName=root
#密码
pwd=root123456

(2) settings 配置标签

settings 元素的作用是设置一些非常重要的设置选项,用于设置和改变 MyBatis 运行中的行为

比如日志:

 <!-- mybatis参数配置标签 -->
    <settings>
        <!-- 配置mybatis的日志用log4j实现 -->
        <setting name="logImpl" value="LOG4J" />
    </settings>

然后在resources文件夹下创建log4j.properties配置文件

######################## ????DEBUG????????consoleh?file?????, console?file?????????
log4j.rootLogger=DEBUG,console,file

########################??????????
log4j.appender.console = org.apache.log4j.ConsoleAppender
#??????
log4j.appender.console.Target = System.out
#?DEBUG????
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
#????
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

######################??????
log4j.logger.org.mybatis=DEBUG   
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

(3)typeAliases配置标签

给java中数据库与实体映射的类编写别名,以简化映射xml文件中返回值或者参数的编写

1.在typeAliases标签中直接配置typeAlias字标签,一个类一个标签的配置

在mybatis配置文件中

<!-- 给pojo类取别名 -->
    <typeAliases>
        <!-- 申明类的别名以及类的全限定名 -->
        <typeAlias alias="studentDo" type="com.huawei.dto.StudentDo"/>
    </typeAliases>

在映射xml中就可以编写别名了

<mapper  namespace="com.huawei.dao.StudentMapper">

    <!-- 查询:根据学生编号查询学生数据 parameterType:代表的是参数类型 resultType:数据返回的类型可以使用别名-->
    <select id="getStudentByCode" parameterType="string" resultType="studentDo">
        select * from student where code = #{code};
    </select>
    
    ... ...

2.自动扫描包下的pojo类生成别名

配置了 typeAliases 元素,在 Mapper.xml 中的 resultType 属性无须写完全限定名com.huawei.pojo.User,只需要写 User 或 user 不区分大小写。

<!-- 给pojo类取别名 -->
    <typeAliases>
        <!-- 自动扫描包的全限定名,自动生成别名 -->
        <package name="com.huawei.dto" />
    </typeAliases>

(4)environments环境配置标签

<configuration>
    <!-- 配置开发环境,可以配置多个,在具体用时再做切换 -->
    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC"></transactionManager>    <!-- 事务管理类型:JDBC、MANAGED -->
            <dataSource type="POOLED">    <!-- 数据源类型:POOLED、UNPOOLED、JNDI -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/huawei?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC" />
                <property name="username" value="root" />
                <property name="password" value="root123456" />
            </dataSource>
        </environment>
    </environments>

(5)mapper映射文件配置标签

在之前的学习中,我们是一个xml映射文件编写一个mapper标签

今天,我们学习自动扫描包完成映射。

注意:这种方式必须保证接口名和 SQL 映射文件名相同,还必须在同一个包中。
如:

mybatis配置文件中的配置方法

<!-- 加载映射文件 mapper -->
    <mappers>
        <!-- 自动扫描com.huawei.dao包下的同名接口和xml映射文件实现关联 -->
        <package name="com.huawei.dao" />
    </mappers>

此时测试调用可能会出现异常:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.huawei.dao.StudentMapper.getStudentList

原因是:xml文件是一个静态文件,且现如今被放置在java源代码目录中,默认情况下idea是会自动排除静态文件进行打包,所以要配置maven静态文件也进行打包:

pom.xml文件中进行配置

<build>
    <finalName>CZ_MyBatisDemo1</finalName>

    <!-- maven静态资源打包 -->
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <!-- 指定路径下的指定后缀的文件也会进行打包 -->
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
          <include>**/*.js</include>
          <include>**/*.css</include>
          <include>**/*.html</include>
        </includes>
        <filtering>false</filtering>
      </resource>
      <resource>
        <directory>src/main/java</directory><!-- 源代码路径下的配置 -->
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include> <!-- 让xml文件也打包 -->
          <include>**/*.js</include>
          <include>**/*.css</include>
          <include>**/*.html</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    ... ...

配置完成之后,使用maven工具-》clean-》install,观察是否成功打包

MapperXMLSQL映射文件配置

(1)Select标签

<select id="getStudentByCode" parameterType="string" resultType="studentDo" >
        select * from student where code = #{code};
    </select>
resultMap属性

作用:实现不同名字段和属性实现关联映射赋值

<!-- 创建结果集映射规则从表字段映射实体字段 -->
    <resultMap id="StudentRes" type="studentDo">
        <id column="code" property="code" />
        <!--  column指定数据库字段名 property指向实体中的属性名-->
        <result column="userName" property="name" />
        <result column="age" property="age" />
    </resultMap>

    <!-- 查询:根据学生编号查询学生数据 resultMap 代表要使用哪个字段和实体的映射规则,值为resultMap标签id值-->
    <select id="getStudentByCode" parameterType="string" resultType="studentDo" >
        select * from student where code = #{code};
    </select>
resultType类型为map

在接口中定义方法

//查询出所有的学生信息放回map集合
    List<Map<String,Object>> getAllStudentData() throws IOException;

xml中编写sql

<select id="getAllStudentData" resultType="map">
        select * from student
    </select>
动态SQL标签

(1)if标签

<!-- 查询所有学生信息(多行数据) -->
    <select id="getStudentList" parameterType="studentDo" resultType="studentDo">
        select * from student where 1=1
        <if test="name!=null or name !=''">
            and userName = #{name}
        </if>
        <if test="age!=0">
            and age = #{age}
        </if>
    </select>

执行结果,根据传递参数的值判断是否拼接if标签中的sql语句

[com.huawei.dao.StudentMapper.getStudentList]-==>  Preparing: select * from student where 1=1 and userName = ? and age = ?
[com.huawei.dao.StudentMapper.getStudentList]-==> Parameters: 张三(String), 47(Integer)
[com.huawei.dao.StudentMapper.getStudentList]-<==      Total: 0

(2)if+where 标签结合

我们有多个条件时,不知道那个回是第一个条件,因为第一个条件前sql要拼接上where关键字,此时可以如下使用,mybatis会自动判断字段先后添加where关键字

<!-- 查询所有学生信息(多行数据) -->
    <select id="getStudentList" parameterType="studentDo" resultType="studentDo">
        select * from student
        <where>
            <if test="name!=null or name !=''">
                 userName = #{name}
            </if>
            <if test="age lte 10">
                 age = #{age}
            </if>
        </where>
    </select>

(3)在使用更新语句时可以使用set+if标签动态update语句

/*更新接口方法*/
//修改学生信息
    int updateStudent(StudentDo studentDo);

sql映射xml文件

<!-- 修改学生信息 -->
    <update id="updateStudent">
        update student
        <set>
            <if test="name!=null or name != ''">
                userName = #{name},
            </if>
            <if test="age!=0">
                age = #{age},
            </if>
        </set>
        where code = #{code}
    </update>

(4)分支条件标签choose+when+otherwise

<select id="getStudentList" parameterType="studentDo" resultType="studentDo">
        select * from student
        <where>
            <!-- 条件分支标签 -->
            <!--
              1.多个when标签执行顺序从上至下判断,如果有一个when标签满足条件后,
              之后的when标签和otherwise标签都不会再判断执行
              2.当所有的when标签都不满足条件,则直接执行otherwise标签内容
              
              if(){//when标签
              
              }else if(){//when标签
              
              }else{//otherwise标签
              
              }
              
             -->
            <choose>
                <when test="code==1">
                    code = 1
                </when>
                <when test="name=='张三'">
                    name = '张三'
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>

(5)foreach循环sql

1.单参数传入list集合的情况

接口定义

//查询学生的编号是否在集合中出现过
    List<StudentDo> getStudentListByCodeList(List<String> codes);

sql映射文件xml

<!--查询学生的编号是否在集合中出现过 -->
    <select id="getStudentListByCodeList" resultType="com.huawei.dto.StudentDo">
        select * from student
        where code in
        <foreach collection="list" item="item" index="index" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </select>

2.单参数传入数组的情况

接口定义

//查询学生的编号是否在数组中出现过
    List<StudentDo> getStudentListByCodeList(String [] codes);

sql映射文件xml

!--查询学生的编号是否在集合中出现过 -->
    <select id="getStudentListByCodeList" resultType="com.huawei.dto.StudentDo">
        select * from student
        where code in
        <foreach collection="array" item="item" index="index" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </select>

执行sql拼接效果

[com.huawei.dao.StudentMapper.getStudentListByCodeList]-==>  Preparing: select * from student where code in ( ? , ? , ? , ? , ? )
[com.huawei.dao.StudentMapper.getStudentListByCodeList]-==> Parameters: 1(String), 2(String), 3(String), 10(String), 12(String)

3.传入一个对象或者map集合,遍历对象中的集合属性或者map中的集合元素

此案例以map元素演示:

接口定义:

//查询学生的编号是否在数组中出现过
    List<StudentDo> getStudentListByCodeList(Map<String,Object> map);

sql映射xml

<!--查询学生的编号是否在集合中出现过 -->
    <select id="getStudentListByCodeList" resultType="com.huawei.dto.StudentDo">
        select * from student
        where code in
        <foreach collection="codeList" item="item" index="index" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </select>

测试调用

@Test
    public void test1() throws IOException {

        //1.加载mybatis配置文件-得到输入流对象
        InputStream resourceAsStream = Resources.getResourceAsStream("myBatisConfig.xml");

        //2.根据配置文件流对象加载出SqlSessionFactory工厂对象(SqlSessionFactory生产连接对象)
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //3.获取数据库连接-SqlSession (类似JDBC中的Connect对象)
        SqlSession sqlSession = factory.openSession();

        //4.通过数据库连接对象调用mybatis映射文件中的sql方法
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        //设置查询参数
        Map<String,Object> map = new HashMap<>();

        List<String> codes = new ArrayList<>();

        codes.add("1");
        codes.add("2");
        codes.add("3");
        codes.add("4");
		//!!!!! 重点 !!!!!!
        map.put("codeList",codes);


        mapper.getStudentListByCodeList(map);

        //5.归还连接(关闭连接)
        sqlSession.close();
    }

mybatis配置连接池(脱离web容器的方法)

(1)引入druid连接池依赖

<!-- 阿里的druid连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
    <scope>compile</scope>
</dependency>

(2)更换连接池的第一步-创建一个工厂类继承PooledDataSourceFactory

/**
 * 创建一个自定义的工厂类,继承PooledDataSourceFactory
 * 重新编写DataSource对象的创建方法
 * 2022/5/31
 */
public class MyDruidPoolFactory extends PooledDataSourceFactory {

    /**
     * 定义构造器,替换dataSource对象的创建方法
     */
    public MyDruidPoolFactory(){
        this.dataSource = new DruidDataSource();
    }
    
}

(3)更换mybatis配置文件中-环境配置数据源标签的type属性

 <!-- dataSource标签的type属性为我们创建的连接池类的全限定名  -->
    <environments default="test">
        <environment id="test">
            <transactionManager type="JDBC"></transactionManager>    <!-- 事务管理类型:JDBC、MANAGED -->
            <dataSource type="com.huawei.config.MyDruidPoolFactory">    <!-- 数据源类型:POOLED、UNPOOLED、JNDI -->
                <!-- 切换为阿里druid连接池后驱动名称变为了 driverClass -->
                <property name="driverClass" value="${driver}" />
                <!-- 切换为阿里druid连接池后连接地址变为了 jdbcUrl -->
                <property name="jdbcUrl" value="${url}" />
                <property name="username" value="${userName}" />
                <property name="password" value="${pwd}" />
            </dataSource>
        </environment>
    </environments>
posted @   忙碌的高师傅  阅读(167)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示