第三阶段(day18)springboot3

 1.springboot跨域配置(重要)

新建项目

 删无用目录

pom.xml中spring-boot-starter-parent版本改为2.3.5.RELEASE,删除没用内容

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.javasm</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1</version>

    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件后缀改成yml(application.yml)

找到启动类Application(也是配置类,主配置类),在启动类所在包建东西。

新建config.BootAppConfig配置类(不需要导入主配置类,只要自己定义的配置类在主配置类的包下就不用。否则在主配置类上加@Import(BootAppConfig.class))--该类加@Configuration就相当于一个.xml配置文件,这里主要注册bean对象(@Bean的方式)。

在前后端分离开发模式下,服务端如何进行跨域设置,springboot中仍然是基于CorsFilter进行跨域设置.

①.方法1:从WebMvcConfigurer接口派生,重写addCorsMapping方法进行跨域配置.

(此方法不建议使用,因为这里是基于springmvc的跨域拦截器进行跨域响应头设置,此拦截器最后一个执行,如果与自定义拦截器一起使用,出现跨域异常.)

用户请求进来,先执行filter过滤器,再执行dispatcherServlet。dispatcherServlet根据url找到对应的拦截器和处理器方法,自定义的拦截器在最上方,最下方是跨域拦截器。所有拦截器通过后,执行处理器方法。若有一个拦截器将请求拦截,返回前端,跨域拦截器就不会执行。跨域拦截器不执行,跨域响应头就没有设置。不返回跨域响应头给前端,前端就报跨域异常。

(也可以解决,只要在自定义拦截器里,将opsession域检请求放行)

②.方法2:使用CorsFilter过滤器对象进行跨域配置

将自定义配置类改名CorsConfig,表示跨域配置。

@Configuration    //相当于建了cors.xml配置文件
public class CorsConfig {

    //注册Bean对象(之前注册CorsFilter对象到容器,然后在web.xml中配置过滤器代理对象,才能在容器中真正获取CorsFilter对象,使它生效)
    //在springboot中没有web.xml了,如何配置Filter过滤器?通过FilterRegistrationBean过滤器注册器对象来配置Filter的信息(过滤器
    //执行顺序,范围...)该对象相当于web.xml中filter标签
    @Bean
    public FilterRegistrationBean cors(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();  //还是web.cors包,是跨域过滤器对象参数
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://localhost:8088");   //允许的客户端域名
        config.setAllowCredentials(true);  //允许客户端携带cookie
        config.addAllowedHeader("*");  //允许的客户端请求头,这里表示所有
        config.addAllowedMethod("*");  //允许的客户端请求方法
        config.addExposedHeader("admin_token");   //若使用token,添加暴露出去的响应头
        source.registerCorsConfiguration("/**",config); //注册跨域配置(对所有请求路径都进行跨域)

        CorsFilter corsFilter = new CorsFilter(source);  //web包下的CorsFilter,创建跨域过滤器对象
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(corsFilter);
        filterRegistrationBean.setOrder(0);  //指定过滤器执行顺序,这里设置第一个执行,任何请求进来,先执行跨域过滤器
        return filterRegistrationBean;
    }

}

但参数在代码里写死了,故将他们移到配置文件。

先建配置对象。这里先建一个公共包commons,并将刚才的config包也拉过去(只要在com.javasm包下都是可以的)。再在公共包下建properties.BootProperties

@ConfigurationProperties(prefix = "boot",ignoreUnknownFields = true)  //获取指定前缀的数据,这里为boot。
//第二个参数为忽略无法识别的字段,默认true,故可省略
@EnableConfigurationProperties(BootProperties.class)
public class BootProperties {

    private List<String> origin;  //客户端地址(服务器接收到的客户端可能不止一个)
    private Boolean credentials;  //是否允许携带cookie
    private List<String> methods;  //可能限定几种方法,其他方法不让进来
    private List<String> headers;  //允许的客户端请求头
    private List<String> exposedHeaders;  //允许暴露的响应头

    public List<String> getOrigin() {
        return origin;
    }

    public void setOrigin(List<String> origin) {
        this.origin = origin;
    }

    public Boolean getCredentials() {
        return credentials;
    }

    public void setCredentials(Boolean credentials) {
        this.credentials = credentials;
    }

    public List<String> getMethods() {
        return methods;
    }

    public void setMethods(List<String> methods) {
        this.methods = methods;
    }

    public List<String> getHeaders() {
        return headers;
    }

    public void setHeaders(List<String> headers) {
        this.headers = headers;
    }

    public List<String> getExposedHeaders() {
        return exposedHeaders;
    }

    public void setExposedHeaders(List<String> exposedHeaders) {
        this.exposedHeaders = exposedHeaders;
    }
}

接下来在配置文件里配这些东西:(yml文件里不能写*)

boot:
  origin: [http://localhost:8088]
  credentials: true
  methods: [GET,POST,PUT,DELETE,OPTIONS]
  heheaders: []
  exposedHeaders: [admin_token]

(集合为空,表示允许所有。)

然后数据就会被加载到BootProperties对象里,CorsConfig类里就可以注入该对象。同时修改方法,比如拿客户端域名不止一个(之前的Addxx方法是一个个往里添,现在是整个集合放进去)。

@Configuration    //相当于建了cors.xml配置文件
public class CorsConfig {

    @Resource   //注入该对象
    private BootProperties bp;

    //注册Bean对象(之前注册CorsFilter对象到容器,然后在web.xml中配置过滤器代理对象,才能在容器中真正获取CorsFilter对象,使它生效)
    //在springboot中没有web.xml了,如何配置Filter过滤器?通过FilterRegistrationBean过滤器注册器对象来配置Filter的信息(过滤器
    //执行顺序,范围...)该对象相当于web.xml中filter标签
    @Bean
    public FilterRegistrationBean cors(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();  //还是web.cors包,是跨域过滤器对象参数
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(bp.getOrigin());  //允许的客户端域名
        config.setAllowCredentials(bp.getCredentials());  //允许客户端携带cookie
        List<String> headers = bp.getHeaders();
        if (headers==null || headers.size()==0){
            config.addAllowedHeader("*");   //没配置请求头,全部加进去
        }else                               //否则按照用户配置的请求头加进去
          config.setAllowedHeaders(headers);
        List<String> methods = bp.getMethods();
        if(methods==null || methods.size()==0)
            config.addAllowedMethod("*");
        else
            config.setAllowedMethods(bp.getMethods());  //允许的客户端请求方法
        List<String> exposedHeaders = bp.getExposedHeaders();
        if(exposedHeaders!=null && exposedHeaders.size()>0)
            config.setExposedHeaders(bp.getExposedHeaders());   //若使用token,添加暴露出去的响应头

        source.registerCorsConfiguration("/**",config); //注册跨域配置(对所有请求路径都进行跨域)
        CorsFilter corsFilter = new CorsFilter(source);  //web包下的CorsFilter,创建跨域过滤器对象
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(corsFilter);
        filterRegistrationBean.setOrder(0);  //指定过滤器执行顺序,这里设置第一个执行,任何请求进来,先执行跨域过滤器
        return filterRegistrationBean;
    }

}

(记住FilterRegistrationBean和CorsFilter两个对象,剩下的靠提示就可以写出来。)

2.Thymeleaf模板引擎(不重要,但最好记着有这么个东西)

①.在同步开发模式下,才会用到,类似jsp这套技术,故不重要,但每个程序员都要掌握一两套这个技术。

同步请求,每次操作都刷新页面;

异步请求,每次操作可以不刷新页面,而是局部修改页面中数据.

②.模板引擎这门技术主要用来做什么?

可以用在做视图模板,在html静态页中添加模板引擎语法,来解析服务端传递来的数据,生成不同效果的动态页.
​
可以用来做代码生成模板,类似easycode插件(生成的模板都是.vm后缀,该后缀是velocity的文件,velocity是基于java的模板引擎。此插件是velocity模板引擎的应用),若依代码生成也用到velocity模板。
​
可以用来做word文件生成模板;基于freemarker模板引擎来生成动态word文件.(用来生成word文件)

③.springboot框架中建议使用thymeleaf引擎作为视图模板技术.

jsp: 编写XX.jsp文件。用户第一次访问jsp文件,jsp引擎生效,解析jsp语法,把访问的jsp文件翻译成XX.java文件。虚拟机jvm再编译成XX.class文件,jvm再次把字节码文件加载到虚拟机内存,再实例化XX对象,再执行对象。service方法,该方法内再生成html文本字符串,输出给客户端。

thymeleaf:从性能以及开发便捷性上,thymeleaf比jsp优秀。编写XX.html(thymeleaf的后缀还是.html文件),用户第一次访问html模板文件,thymeleaf引擎解析语法,把模板文件直接解析到内存中,接收动态数据,生成静态html输出前端。(直接在内存中解析,执行流程少了很多)同时

thymeleaf的语法更丰富,jsp做不到的事,它可以做到。

④.thymeleaf引擎在springboot框架中使用

添加thymeleaf启动器,一旦引入该启动器,则spring-boot-starter-autoconfiguration包下的ThymeleafAutoConfiguration预配置类生效,该配置类中注册了ThymeleafViewResolver视图解析器对象.

在pom.xml文件中:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在templates目录下新建login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>登录页</h1>
    <form action="/user/dologin" method="post">
        用户名:<input name="uname">
        <br>
        密码:<input type="password" name="upwd">
        <br>
        <button type="submit">登录</button>
    </form>
</body>
</html>

在templates目录下新建main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>主页。欢迎:这里显示登录用户</h1>
</body>
</html>

这两个页面前端无法直接访问,因为只有静态目录static下的内容前端才可以直接访问。

故需要后端处理器方法返回页面。在javasm包下新建sys.controller.UserController

//不要用@restController,它表示返回json数据给前端,所有的同步开发模式下都是返回视图给前端,故用@Controller
@Controller
@RequestMapping("user")   //第一层url
public class UserController {

    @PostMapping("dologin")     //第二层url
    public String dologin(String uname, String upwd){  
        if("admin".equals(uname) && "123".equals(upwd)){
            System.out.println("suc");
            return "main";
        }else {
            return "login";    //密码有误,还停留在登录页面
            //thymeleafViewResolver中会拼接视图前缀和后缀    classpath:/templates/login.html
        }
    }

}

若希望在返回的视图加一些东西:

//不要用@restController,它表示返回json数据给前端,所有的同步开发模式下都是返回视图给前端,故用@Controller
@Controller
@RequestMapping("user")   //第一层url
public class UserController {

   @PostMapping("dologin")
    public String dologin(String uname, String upwd, Model m){  //若向登录页面带一些数据,可加Model对象,向该对象加数据即可
        if("admin".equals(uname) && "123".equals(upwd)){
            System.out.println("suc");
            m.addAttribute("loginUname",uname);
            return "main";
        }else {
            m.addAttribute("msg","用户名密码错误");
            return "login";    //密码有误,还停留在登录页面
            //thymeleafViewResolver中会拼接视图前缀和后缀    classpath:/templates/login.html
        }
    }
}

现在还是访问不到,因为templates不是静态目录。

故还需要加方法

//不要用@restController,它表示返回json数据给前端,所有的同步开发模式下都是返回视图给前端,故用@Controller
@Controller
@RequestMapping("user")   //第一层url
public class UserController {

    @GetMapping("login")    //用户访问user/login,进入这个方法,该方法又返回一个字符串视图路径,才会找到templates目录下的login.html
    public String login(){
        return "login";
    }

   @PostMapping("dologin")
    public String dologin(String uname, String upwd, Model m){  //若向登录页面带一些数据,可加Model对象,向该对象加数据即可
        if("admin".equals(uname) && "123".equals(upwd)){
            System.out.println("suc");
            m.addAttribute("loginUname",uname);
            return "main";
        }else {
            m.addAttribute("msg","用户名密码错误");
            return "login";    //密码有误,还停留在登录页面
            //thymeleafViewResolver中会拼接视图前缀和后缀    classpath:/templates/login.html
        }
    }
}

这就是同步开发,每一次操作返回给前端的都是视图,带着数据和视图一起返回前端。

(“login”   “main” 这些就是视图模板。)

测试:

 登录失败,登录页面应该返回错误信息。获取服务端回传到视图模板里的数据需要用到thymeleaf的语法。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>登录页</h1>
    <form action="/user/dologin" method="post">
        用户名:<input name="uname">
        <br>
        密码:<input type="password" name="upwd">
        <br>
        <div>
            <span style="color:red">[[${msg}]]</span>
        </div>
        <button type="submit">登录</button>
    </form>
</body>
</html>

ctrl+F9重新发布,故意打错密码。

同理main页面在登录成功后也可以得到登录用户名:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>主页。欢迎:[[${loginUname}]]</h1>
</body>
</html>

ctrl+F9,在登录页输入正确的用户名和密码,跳转到主页面

 这样就使得静态的页面变成了动态的内容。

⑤.学习thymeleaf的语法:

1.thymeleaf表达式:

a.属性表达式:${}.---------必须配合th:text属性

作用:用来获取服务端request,session,servletContext域对象中的数据.

语法:request域数据获取:${key}    session域数据获取:${session.key}或者${#session.getAttribute('key')}      servletContext域数据获取:${#servletContext.getAttirubte('key')}

 前端获取数据

(获取到request域里的数据,给双标签span中间的内容赋值,中间的a被覆盖)

 登录成功后:

 (当然,若key写错,获取null,相当于null覆盖中间的a)

 其他几个:

测试:

 (以上顺便讲了th:value   th:text)

b.链接表达式:@{}------(th:href th:src th:action)

作用:为src/href等url链接属性补全项目根路径

注意点:url中如何传递参数 <a th:href="@{/user/del(id=1,uname=${loginUname})}">点我</a>

在static目录下新建imgs目录,放一张图,浏览器可直接访问

 现在想在main页面显示该图片

图片太大,修改下尺寸。src里应为/imgs/a.jpg

 

 现在部署路径为空,若手工指定部署路径为/boot

 此时再访问,请求路径要加boot

 输入用户名密码,还是报错

 因为action写的/开头,表示绝对路径的写法。

绝对路径即端口后边开始算,即根开始算。

需要改为action="/boot/user/dologin",即加上部署路径。但这样写死了,部署路径发生改变后,就得修改。

怎么办?---写相对路径。action="dologin"

进入登录页面,写错误用户名密码后就可以停留在登录页面。

相对路径:没有/开头,相对当前路径。那就需要知道该页面当前是在哪个路径。

 这个login是在user/login路径下。

或者也可以看这里

是在boot/user/login路径下。

 相对当前路径,当前login在user下,故去user下找同级的dologin

以上容易搞晕,此时,thymeleaf出现:

链接表达式的地址必须/开头的根路径,即绝对路径,但不需要考虑项目部署路径,会自动补上。

 

访问图片时也不用加部署路径

<Br>
<img th:src="@{/imgs/a.jpg}" style="height: 150px;width: 150px">

后端再加个删除方法

 前端对接后端的该方法,并传递参数:

后端该方法打断点,可以收到del:1,uname:null。但不建议这样用

 此时若uname要传递的是request里的参数

会将${loginUname}整体作为参数传递,而${}作为特殊符号,不能传递,就报错了。

 链接表达式里传递参数,不建议用?而是用()

这个主要用在修改里。

除了form表单标签,用link标签引入其他文件也会用到链接表达式

在Static目录下新建css目录,目录下新建main.css

body{
    background-color: teal;
}

此时,写绝对路径引入

(部署路径改为了b) 

若用链接表达式

引入js文件同理

 

在开发中thymeleaf是个神器!!!

c.文档表达式:~{}

作用:进行公共页的嵌套。

网站的顶部和底部都是公共页。可将顶部和底部的页面提出来成为公共页面。

在templates目录下新建commons目录,新建top.html

<div>
    这里是顶部公共页
</div>

想将top页面嵌入到main页面

 会自动拼接路径前缀和后缀,效果:

 

它是在th:insert所在标签里面放入div。(将top.html里的内容整个插入到标签里面)

 另一种方法:

<!--/tempaltes/commons/top.html-->
<div th:replace="~{commons/top}"></div>

他是将top.html整个div放入到main.html。(将th:replace所在标签替换掉)

局部嵌套这样来:(fragment片段)-------引用页面当中的某个片段

在top.html中:

<div th:fragment="topDiv">
    这里是顶部公共页
</div>

<div th:fragment="footDiv">
    这里是底部内容
</div>

在main.html中:

body标签的最上面:

<!--/tempaltes/commons/top.html-->
<div th:replace="~{commons/top :: topDiv}"></div>

body标签的最下面:

<div th:replace="~{commons/top :: footDiv}"></div>

效果:

2.thymeleaf属性:写在html标签属性处.

th:value: 作用:结合属性表达式${}使用,为单标签指定内容

th:text 作用:结合属性表达式${}使用,为双标签指定内容      简写:[[${}]]

th:href th:src th:action 作用:这三个属性,结合链接表达式@{}使用,用在img,link,script,a,form标签上,补全项目根路径 示例:<a th:href="@{/user/del(id=1,uname=${loginUname})}">点我</a>

th:insert th:replace: 作用:这两个属性,结合文档表达式实现公共页嵌套. 实例:<div th:replace="~{commons/top}"></div>

th:fragment: 作用:结果文档表达式实现局部页嵌套 实例:公共内容:<div th:fragment="topDiv">这里是顶部公共</div> 页面:<div th:replace="~{commons/top :: footDiv}"></div>

th:each: 实例:<tr th:each="u,s : ${key}">

th:if: 实例:<tr th:each="u,s : ${ll}"

th:if="${s.count%2==0}">

循环与判断属性:

在进入main页面前,向Model对象加入集合数据:

在sys包下新建entity.Users

 在main页面显示一个表格数据,需要用th:each遍历key为ll的集合数据,需要用到循环变量 

 效果:

 也可以有两个循环变量,用逗号分隔。

 

 u是s的一部分。s.current就是u。s.count可以用来做序号。这是前端的序号,和id是不一样的概念。之前说过,从来不会将用户id显示给前端看的。

 id是用来做修改删除用的。比如现在有个操作列:

<table>
    <thead>
    <tr>
        <td>seq</td>
        <td>uname</td>
        <td>uphone</td>
        <td>uage</td>
        <td>edit</td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="u,s : ${ll}">
        <td>[[${s.count}]]</td>
        <td>[[${u.uname}]]</td>
        <td>[[${u.uphone}]]</td>
        <td>[[${u.uage}]]</td>
        <Td>
            <a th:href="@{/users/update(id=${u.id})}">修改</a>
            <a th:href="@{/users/del(id=${u.id})}">删除</a>
        </Td>
    </tr>
    </tbody>
</table>

th:if用来做判断,比如只显示偶数行的数据:(它里面必须是布尔表达式)

<table>
    <thead>
    <tr>
        <td>seq</td>
        <td>uname</td>
        <td>uphone</td>
        <td>uage</td>
        <td>edit</td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="u,s : ${ll}" th:if="${s.count%2==0}">
        <td>[[${s.count}]]</td>
        <td>[[${u.uname}]]</td>
        <td>[[${u.uphone}]]</td>
        <td>[[${u.uage}]]</td>
        <Td>
            <a th:href="@{/users/update(id=${u.id})}">修改</a>
            <a th:href="@{/users/del(id=${u.id})}">删除</a>
        </Td>
    </tr>
    </tbody>
</table>

3.log4j2整合

在项目中整合log4j2日志,与slf4j日志门面组件

在spring-boot-starter依赖中引入了spring-boot-starter-logging启动器,该启动器使用logback依赖.要把这个logback日志替换成log4j2.(同一个项目中绝对不能有两个日志组件,会报错,因为slf4j日志门面的问题,该日志门面会检测当前项目下的具体日志组件,如果有多个,直接给出异常。日志组件只能有一个。 )

 

①.排除logging启动器

操作后,该组件消失。 

(必须在第一个引入该日志包的依赖里排除它。看左侧依赖包谁在最上面,就从谁的里面排除该包)

②.添加log4j2启动器

若想不起来咋添加,可在两个地方找:

去maven官网找(推荐)

 搜索log4j2

也可去spring.io官网找(全英文,不好找)

复制相关代码到pom文件

③.添加log4j2.xml文件

直接拷贝之前的项目,将log4j2.xml复制到resources目录下

若使用它

④.如果要使用异步日志,需要引入disruptor组件,lmax公司开源异步非阻塞队列. 

在pom文件加入:

 <dependency>
     <groupId>com.lmax</groupId>
     <artifactId>disruptor</artifactId>
     <version>3.4.2</version>
 </dependency>

同时在log4j2.xml中改变配置方式:(将同步更换为异步)

4.mybatis整合

①.添加mysql驱动包

 <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
 </dependency>

②.添加druid环境,是单个jar包还是有对应启动器呢?mysql驱动包为啥没有启动器?

druid是有启动器的。有启动器优先使用启动器,启动器里含着对应的jar包。

何时有启动器?何时没有? 即什么时候组件会封装启动器?

如果这个组件需要注册对象到spring容器,那么一般都会有对应的starter.

如果没有,只能手工添加依赖包,自己注册对象。如何注册?建一个Config类

 大多数需要注册到容器的都会有启动器的。

组件的启动器一般都是组件名+AutoConfigure

添加druid启动器,查看DruidDataSourceAutoConfigure预配置类,该配置类早于DataSourceAutoConfiguration配置类.在Druid配置类中已经注册了DruidDataSourceWrapper连接池对象

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

指定用户名密码等信息(Driver的包是cj.jdbc.Driver,现在mysql驱动是8.0版本,之前是5.0版本)

(datasource下有username,druid下也有username,url等也是。用哪个都可以)

(新版的驱动类必须指定时区)

(要指定连接池的类型是DruidDataSource对象,可以不指,但引进mybatis启动器后,会引入新的数据库连接池,叫HikariCP:3.4.5连接池。故,不指定,就会创建HikariDataSource连接池(日本的)。)

(设置初始连接数为5)

(要想配置齐全,可以到课件里去找)

 在application.yml中: 

boot:
  origin: [http://localhost:8088]
  credentials: true
  methods: [GET,POST,PUT,DELETE,OPTIONS]
  heheaders: []
  exposedHeaders: [admin_token]
server:
  servlet:
    context-path: /b
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/704a?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 5

测试:

更新仓库(引得jar包多了,就更新一下。对本地仓库所有jar包文件进行扫描,创建索引号,创建索引文件,便于查找仓库的东西)

 

 启动后,初始会有5个连接对象,是druidDataSource

  

③.添加mybatis启动器,查看MybatisAutoConfiguration预配置类,在该配置类中依赖DataSource对象,注册SqlSessionFactory对象到spring容器.还注册了MapperScannerConfigurer对象.

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>

该启动器还会引入jdbc启动器。

④.在yml文件中配置mybatis映射文件路径

在resource目录下建mapper包,再按照模块划分(sys系统管理模块,orders订单模块,cards卡管理模块...)

在application.yml中添加: 

mybatis:
  mapper-locations: classpath:/mapper/*/*.xml
  type-aliases-package: com.javasm
  configuration:
    map-underscore-to-camel-case: true

(本地映射文件的路径,必须有。剩下的都可以不要)

(mybatis别名包的范围)

在src.main.java.com.javasm.sys下创建dao,service包。

 dao包新建UserDao

public interface UserDao {
    Users getById(String id);


}

在mapper.sys下创建映射文件user-mapper:

<?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="com.javasm.sys.dao.UserDao">
    
</mapper>

在UserDao的方法上alt+回车生成方法。

<?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="com.javasm.sys.dao.UserDao">
    <select id="getById" resultType="com.javasm.sys.entity.Users">
        select * from sys_user where id=#{id}
    </select>
</mapper>

测试

 想用mybatis,还要注入SqlSessionFactory,然后从它里面打开Session,再从Session得到dao接口的代理对象。

在ssm整合那里,注入SqlSessionFactory后,使用MapperScannerConfigurer  dao接口扫描器对象把指定包下的dao接口全部创建代理对象注册容器。

这里mybatis预配置对象,底层把com.javasm包下的所有接口都创建代理对象。

service包下新建IUserService接口:

public interface IUserService {
    Users getById(String id);
   

}

实现类

@Service将该接口注入容器,service依赖dao,@Resource将dao取出。

 mybatis预配置对象会将IUserService创建代理对象注册到容器,对dao的接口也创建代理对象注册到容器。如果controller依赖于service

 这里注入就不行了,因为类型为IUserService的对象容器里有两个。

开启@MapperScan  接口扫描

此时报没有唯一bean定义异常。

 

conrtoller依赖的service不能用(先注释掉),此时测试时,直接从容器取出dao,用就行。

@SpringBootTest
class ApplicationTests {

    @Resource
    private DataSource ds;

    @Resource   //从容器里拿到SqlSessionFactory对象
    private SqlSessionFactory f;

    @Resource
    private UserDao ud;

    @Test
    void contextLoads() {
        Users byId = ud.getById("1");
    }

}

如何才能让service用起来,就是向ssm整合一样,指向dao接口所在包名,而不是com.javasm下的所有接口。

⑤.在配置类中启用接口扫描,并指定dao接口的具体包名

@MapperScan(basePackages = "com.javasm.*.dao")  //启用接口扫描,并指定dao接口的具体包名

5.事务整合

这个非常简单,不用添加任何依赖,任何配置,因为在DataSourceTransactionManagerAutoConfiguration预配置类,已经注册了DataSourceTransactionManager对象,并依赖DataSource.

①.开启事务注解识别:

@SpringBootApplication
@MapperScan(basePackages = "com.javasm.*.dao")
@EnableTransactionManagement    //启用事务注解识别
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

②.在服务层的方法上添加@Transactional注解即可.(哪个方法需要开启事务,就在类上加@Transactional注解)

@Service   //注入容器
public class UserServiceImpl implements IUserService {
    @Resource   //service依赖dao,从容器获取
    private UserDao ud;

    //只对RunTimeException异常生效,进行回滚,如果方法抛出的编译时异常,并不能触发回滚.如果需要回滚
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Users getById(String id) {
        return null;
    }

    @Override
    public List<Users> list() {

        return ud.list();
    }
}

将注解放在Application,会使启动类很乱,在config目录下新建DaoConfig类,去承载这些注解。

6.分页整合

分页组件也有启动器,PageInterceptor拦截器对象需要注册进入SqlSessionFactory对象的plugins属性.

在这个启动器中,有PageHelperAutoConfiguration预配置类.此配置类实例化PageInterceptor,并把分页拦截器注册到了SqlSessionFactory.

(每个组件都必须找到配置类来看他!!若不找到配置类看他,用springboot就会很晕)

 

①.添加分页启动器

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>

(小组件没有引过去,需要指定版本)

在controller包下新建UserController2类:

@RestController
@RequestMapping("u")
public class UserController2 {

    @Resource
    private IUserService us;
    
    @GetMapping("list")
    public ResponseEntity userslIst(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "2") Integer pageSize){
        PageHelper.startPage(pageNum,pageSize);

        List<Users> l = us.list();

        PageInfo i = new PageInfo(l);
        return ResponseEntity.ok(i);
    }

}
public interface IUserService {
    Users getById(String id);

    List<Users> list();

}
@Service   //注入容器
public class UserServiceImpl implements IUserService {
    @Resource   //service依赖dao,从容器获取
    private UserDao ud;

    //只对RunTimeException异常生效,进行回滚,如果方法抛出的编译时异常,并不能触发回滚.如果需要回滚
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Users getById(String id) {
        return null;
    }

    @Override
    public List<Users> list() {

        return ud.list();
    }
}
public interface UserDao {
    Users getById(String id);

    List<Users> list();

}
<?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="com.javasm.sys.dao.UserDao">
    <select id="getById" resultType="com.javasm.sys.entity.Users">
        select * from sys_user where id=#{id}
    </select>

    <select id="list" resultType="com.javasm.sys.entity.Users">
        select * from sys_user order by update_time desc
    </select>
</mapper>

dabug运行

②.在yml中设置分页合理化

pagehelper:
  reasonable: true

此时访问-1

给的就是第一页

访问234

就是最后一页

不会出现空记录。 

不要硬件怎么配置的,只要知道加了启动器,就去搜索它的配置类,去配置类看他用的配置对象是谁,去那里面找数据。

 

7.aop 

①.添加aop启动器

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
 

②.启用aop注解识别

 

commons包下新建aspect.LogAspect

 @Aspect定义切面对象    @Pointcut切入点定义     @Around环绕通知

 

总结:

除了模板引擎以外,都在项目中使用。

跨域配置不需要死记。拷贝就行。

log4j2,拷贝就行

其他的必须阅读预配置类,关注组件内的核心对象创建过程,关注以来的XXXXXProperties配置对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值