主頁 > 後端開發 > Spring 5

Spring 5

2022-10-03 06:28:48 後端開發

Spring 5框架

一、Spring概念

1、Spring是輕量級的JavaEE框架

2、Spring可以解決企業應用開發的復雜性

3、Spring有兩個核心部分:IOC和AOP

? 1)IOC:控制反轉,把創建物件程序交給Spring進行管理

? 2)AOP:面向切面,不修改源代碼進行功能增強

4、Spring特點

  1. 方便解耦,簡化開發
  2. AOP編程的支持
  3. 方便程式的測驗
  4. 方便集成各種優秀框架(方便整合其他框架)
  5. 方便進行事務操作
  6. 降低API開發難度

入門案例:

1.下載地址:https://repo.spring.io/ui/native/release/org/springframework/spring

2.打開idea,新建java專案(專案例子檔案:Java/Spring at main · DFshmily/Java (github.com))

3.匯入Spring5相關jar包

image

image

4.創建普通類,在這個類創建普通方法

public class User{
    public void add(){
        System.out.println("add......");
    }
}

5.創建Spring組態檔,在組態檔創建物件

Spring組態檔使用xml格式,創建在src下

image

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

    <!--配置User物件創建-->
    <bean id="user" ></bean>
</beans>

6.進行代碼測驗撰寫

User.java

package com.spring;

public class User {
    public void add(){
        System.out.println("add......");
    }
}

TestSpring.java

package com.spring.testdemo;

import com.spring.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestSpring {
    @Test
    public void testAdd(){
        //1.加載spring組態檔
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //2.獲取配置創建的物件
        User user = context.getBean("user",User.class);
        System.out.println(user);
        user.add();
    }

}
運行結果:
com.spring.User@506ae4d4
add......

二、IOC框架

1.IOC底層原理

(1)什么是IOC

? 1)控制反轉,把物件創建和物件之間的呼叫程序,交給Spring進行管理

? 2)使用IOC目的:為了耦合度降低

? 3)做入門案例就是IOC實作

(2)原理

? 1)xml決議、工廠模式、反射

? image

image

IOC程序:

  1. 第一步xml組態檔,配置創建的物件
 <bean id="user" ></bean>
  1. 有service類和dao類,創建工廠類

    class UserFactory{
        public static UserDao getDao(){
            String classValue = https://www.cnblogs.com/DFshmily/p/class屬性值;//xml決議
            Class clazz = Class.forName(classValue);//通過反射創建物件
            return (UserDao)clazz.newInstance();
        }
    }
    

2.IOC介面(BeanFactory)

(1)IOC思想基于IOC容器完成,IOC容器底層就是物件工廠

(2)Spring提供IOC容器實作兩種方式:(兩個介面)

? 1)BeanFactory:IOC容器基本實作方式,是Spring內部的使用介面,不提供開發人員進行使用

? 加載組態檔的時候不會創建物件,在獲取物件(使用)時才創建

? 2)ApplicationContext:BeanFactory介面的子介面,提供更多更強大的功能,一般由開發人員進行使用

? 加載組態檔時候就會把在組態檔的物件進行創建

(3)ApplicationContext介面實作類

image

3.IOC操作Bean管理(基于xml方式)

(1)什么是Bean管理

? 1)Spring創建物件

? 2)Spring注入屬性

(2)Bean管理操作有兩種方式

? 1)基于xml組態檔方式實作

? 2)基于注解方式實作

(3)基于xml方式創建物件

 <!--配置User物件創建-->
    <bean id="user" ></bean>

? 1)在spring組態檔中,使用bean標簽,標簽里面添加對應屬性,就可以實作物件創建

? 2)在bean標簽有很多屬性,介紹常用的屬性

id屬性:唯一標識
class屬性:類全路徑(包類路徑)

? 3)創建物件的時候,默認也是執行無參構造方法完成物件的創建

(4)基于xml方式注入屬性

? 1)DI:依賴注入,就是注入屬性

? ?第一種注入方式:使用set方法注入

package com.spring;

public class Book {
    private String bname;

    public void setBname(String bname) {
        this.bname = bname;
    }
}

xml:

  <!--set方法注入屬性-->
    <bean id="book" >
        <!--使用property完成屬性注入
        name:類里面屬性名稱
        value:向屬性注入的值-->
    <property name="bname" value="https://www.cnblogs.com/DFshmily/p/shmily"></property>
    </bean>

Test:

public class TestSpring {
    @Test
    public void OrdersTest(){
        //1.加載spring組態檔
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //2.獲取配置創建的物件
        Book book = context.getBean("book",Book.class);
        System.out.println(book);
        book.toString();
    }
}
運行結果:
    Book{bname='shmily'}

? ?第二種注入方式:使用有參構造進行注入:

? 1)創建類,定義屬性,創建屬性對應有參構造方法

    private String oname;
    private String address;
    
    //有參構造
    public Orders(String oname, String address) {
        this.oname = oname;
        this.address = address;
    }

? 2)在Spring組態檔中進行配置

  <!--有引數構造注入屬性-->
    <bean id="orders" >
        <constructor-arg name="oname" value="https://www.cnblogs.com/DFshmily/p/PC"></constructor-arg>
        <constructor-arg name="address" value="https://www.cnblogs.com/DFshmily/p/china"></constructor-arg>
        還有個索引注入 <constructor-arg index="0" value="https://www.cnblogs.com/DFshmily/p/china"></constructor-arg>,"0"是下標
    </bean>

? Test:

public class TestSpring {
    @Test
    public void OrdersTest(){
        //1.加載spring組態檔
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //2.獲取配置創建的物件
        Orders orders = context.getBean("orders",Orders.class);
        System.out.println(orders);
        orders.toString();
    }
}

運行結果:
    Orders{oname='PC', address='china'}

?第三種:p名稱空間注入

? 1)使用p名稱空間注入,可以簡化基于xml配置方式

? ①添加p名稱空間在組態檔中:

    xmlns:p="http://www.springframework.org/schema/p"

? ②進行屬性注入,在bean標簽里面進行操作

    <bean id="book"  p:bname="書"></bean>

4.IOC操作Bean管理(xml其他型別屬性)

? (1)字面量

? 1)null值

<!--null值-->
     <property name="address">
    <null/>
    </property>

? 2)屬性值包含特殊符號

<!--屬性值包含特殊符號
    1.把<>進行轉義
    2.把帶特殊符號內容寫到CDATA
    -->
     <property name="address">
    	<value><![CDATA[<<南京>>]]</value>
        </property>

(2)注入屬性--外部bean

? 1)創建兩個類service類和dao類

? 2)在service呼叫dao里面的方法

public class UserService {
    public void add(){
        System.out.println("service add......");
    }

    //原始方式:創建UserDao物件
    /*UserDao userDao = new UserDaoImpl();
            userDao.update();*/

    //創建UserDao型別屬性,生成set方法
    private UserDao userDao;

    public void setUserDao(UserDaoImpl userDao) {
        this.userDao = userDao;
    }
}

? 3)在spring組態檔進行配置

<!--    1.service和dao物件創建-->
    <bean id="userService" >
    <!--注入userDao物件
        name屬性:類里面屬性名稱
        ref屬性:創建userDao物件bean標簽id值
        -->
    <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    <bean id="userDaoImpl" ></bean>
 @Test
    public void testAdd(){
        //1.加載spring組態檔
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        //2.獲取配置創建的物件
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();
    }

(3)注入屬性--內部bean和級聯賦值

? 1)一對多關系:部門和員工

? 一個部門有多個員工,一個員工屬于一個部門

? 部門是一,員工是多

? 2)在物體類之間表示表示一對多關系,員工表示所屬部門,使用物件型別屬性進行表示

//部門類
public class Dept {
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }
}

//員工類
public class Emp {
    private String ename;
    private String gender;

    //員工屬于某一個部門,使用物件形式表示
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

? 3)在spring組態檔進行配置

    <!--內部bean-->
    <bean id="emp" >
        <!--設定兩個普通屬性-->
        <property name="ename" value="https://www.cnblogs.com/DFshmily/p/shmily"></property>
        <property name="gender" value="https://www.cnblogs.com/DFshmily/p/男"></property>
        <!--設定物件型別屬性-->
        <property name="dept">
            <bean id="dept" >
                <property name="dname" value="https://www.cnblogs.com/DFshmily/p/部門"></property>
            </bean>
        </property>
    </bean>

4)注入屬性--級聯賦值

  1. 第一種:
<!--級聯賦值-->
    <bean id="emp" >
    <!--設定兩個普通屬性-->
    <property name="ename" value="https://www.cnblogs.com/DFshmily/p/shmily"></property>
    <property name="gender" value="https://www.cnblogs.com/DFshmily/p/男"></property>
        
        <!--級聯賦值-->
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" >
        <property name="dname" value="https://www.cnblogs.com/DFshmily/p/部門"></property>
    </bean>
  1. 第二種:
  <!--級聯賦值-->
    <bean id="emp" >
    <!--設定兩個普通屬性-->
    <property name="ename" value="https://www.cnblogs.com/DFshmily/p/shmily"></property>
    <property name="gender" value="https://www.cnblogs.com/DFshmily/p/男"></property>
        
        <!--級聯賦值,用dept.dname時要生成get方法-->
        <property name="dept" ref="dept"></property>
        <property name="dept.dname" value="https://www.cnblogs.com/DFshmily/p/部門"></property>
    </bean>
    <bean id="dept" >
        <property name="dname" value="https://www.cnblogs.com/DFshmily/p/部門"></property>
    </bean>

5.IOC操作Bean管理(xml注入集合屬性)

(1)注入陣列型別屬性

(2)注入List集合型別屬性

(3)注入Map集合型別屬性

? 1)創建類,定義陣列、list、map、set型別屬性,生成對應set方法

package com.spring;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Stu {
    //1.陣列型別屬性
    private String[] courses;

    //2.List集合型別屬性
    private List<String >list;

    //3.Map集合型別屬性
    private Map<String,String> maps;

    //4.set集合型別屬性
    private Set<String> sets;
    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }
}

? 2)在spring組態檔配置

    <!--集合型別屬性注入-->
    <bean id="stu" >
        <!--陣列型別屬性注入-->
        <property name="courses">
            <array>
                <value>java課程</value>
                <value>MySQL</value>
            </array>
        </property>
<!--        或者:list屬性注入-->
        <property name="list">
            <list>
                <value>D</value>
                <value>F</value>
            </list>
        </property>
<!--        map型別屬性注入-->
        <property name="maps">
            <map>
                <entry key="JAVA" value="https://www.cnblogs.com/DFshmily/p/java"></entry>
                <entry key="C" value="https://www.cnblogs.com/DFshmily/p/c"></entry>
            </map>
        </property>
<!--        set型別屬性注入-->
        <property name="sets">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>
    </bean>

Test:

package testdemo;

import com.spring.Stu;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StuTest {
    @Test
    public void testCollection(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        Stu stu = context.getBean("stu",Stu.class);
        stu.test();
    }
}
運行結果:
[java課程, MySQL]
[D, F]
{JAVA=java, C=c}

(4)在集合里面這種物件型別值

       <!--創建多個course物件-->
        <bean id="course1" >
            <property name="cname" value="https://www.cnblogs.com/DFshmily/p/名字1"></property>
        </bean>
    <bean id="course2" >
        <property name="cname" value="https://www.cnblogs.com/DFshmily/p/名字2"></property>
    </bean>
        <!--        注入list集合型別,值是物件-->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>
    </bean>

(5)把集合注入部分提取出來

? 1)在spring組態檔中參考名稱空間util

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

</beans>

? 2)使用util標簽完成list集合注入

<!--    1.提取list集合型別屬性注入-->
    <util:list id="bookList">
        <value>如何閱讀一本書</value>
        <value>java</value>
        <value>C</value>
    </util:list>
<!--    2.提取list集合型別屬性注入使用-->
    <bean id="book" >
        <property name="list" ref="bookList"></property>
    </bean>

6.IOC操作Bean管理(FactoryBean)

(1)Spring有兩種型別bean:一種普通bean,另一種工廠bean(FactoryBean)

(2)普通bean:在組態檔中定義bean型別就是回傳型別

(3)工廠bean:在組態檔定義bean型別可以和回傳型別不一樣

? 1)第一步 創建類,讓這個類作為工廠bean,實習介面FactoryBean

? 2)第二步 實作介面里面的方法,在實作的方法中定義回傳的bean型別

MyBean.java

package com.factorybean;

import com.spring.Course;
import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean<Course> {
    //定義回傳bean
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("dzq");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

Test:

package testdemo;

import com.spring.Course;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class factorybeanTest {
    @Test
    public void testCollection1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
        Course course = context.getBean("myBean", Course.class);
        System.out.println(course);
    }
}

組態檔:

<bean id="myBean" >

    </bean>

7.IOC操作Bean管理(bean作用域)

(1)在Spring里面,設定創建bean實體時單實體還是多實體

(2)在Spring里面,默認情況下bean是單實體物件

    @Test
    public void testCollection2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        Book book1 = context.getBean("book",Book.class);
        Book book2 = context.getBean("book",Book.class);
        System.out.println(book1);
        System.out.println(book2);
    }

運行結果:
com.spring.Book@6cb107fd
com.spring.Book@6cb107fd
    
 因為book1和book2的地址相同,所以他們是單實體物件

(3)如何設定單實體還是多實體

? 1)在spring組態檔bean標簽里面有屬性(scope)用于設定單實體還是多實體

? 2)scope屬性值

第一個值 默認值:singleton,表示單實體物件

第二個值 prototype,表示多實體物件

 <bean id="book"  scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>
運行結果:
com.spring.Book@710636b0
com.spring.Book@3de8f619
   
 它們地址不同,現在是多實體物件  
 

? 3)singleton和prototype區別

? 1.singleton單實體,prototype多實體

? 2.設定scope值是singleton時候,加載spring組態檔的時候就會創建單實體物件

? 設定scope值是prototype時候,不是在加載spring組態檔時候創建物件,在呼叫getBean方法時候創建多實體物件

? 了解:request:每一次HTTP請求都會創建一個新的bean實體,該bean僅在當前HTTP request內有效,在請求完成后,bean會失效并被垃圾回收器回收,

? session:每一次HTTP請求都會創建一個新的bean,該bean僅在當前HTTP session內有效,同一個session會話共享一個實體,不同的會話使用不同的實體,

8.IOC操作Bean管理(bena生命周期)

(1)生命周期

? 1)從物件創建到物件銷毀的程序

(2)bean生命周期

? 1)通過構造器創建bean實體(無引數構造)

? 2)為bean的屬性設定值和對其他bean參考(呼叫set方法)

? 3)呼叫bean的初始化的方法(需要進行配置初始化的方法)

? 4)bean可以使用了(物件獲取到了)

? 5)當容器關閉時候,呼叫bean的銷毀的方法(需要進行配置銷毀的方法)

(3)演示bean的生命周期

例子:

package com.bean;

public class Orders {


    private String oname;

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

    //1.無參構造
    public Orders() {
        System.out.println("第一步 執行無引數構造創建bean實體");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步 呼叫set方法設定屬性值");
    }

    //創建執行的初始化的方法
    private void initMethod(){
        System.out.println("第三步 執行初始化的方法");
    }

    //創建執行的銷毀的方法
    public void destroyMethod(){
        System.out.println("第五步 執行銷毀的方法");
    }
}


組態檔:

 <bean id="orders"  init-method="initMethod" destroy-method="destroyMethod">
        <property name="oname" value="https://www.cnblogs.com/DFshmily/p/手機"></property>
    </bean>

Test:

public class OrdersTest {
    @Test
    public void orderTset(){
//        ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("第四步 獲取創建bean實體物件");
        System.out.println(orders);


        //手動讓bean實體銷毀
        context.close();
    }

    
運行結果:
第一步 執行無引數構造創建bean實體
第二步 呼叫set方法設定屬性值
第三步 執行初始化的方法
第四步 獲取創建bean實體物件
Orders{oname='手機'}
第五步 執行銷毀的方法

(4)bean的后置處理器,bean的生命周期有七步

? 1)通過構造器創建bean實體(無引數構造)

? 2)為bean的屬性設定值和對其他bean參考(呼叫set方法)

? 3)把bean實體傳遞給bean后置處理器的方法postProcessBeforeInitialization

? 4)呼叫bean的初始化的方法(需要進行配置初始化的方法)

? 5)把bean實體傳遞給bean后置處理器的方法postProcessAfterInitialization

? 6)bean可以使用了(物件獲取到了)

? 7)當容器關閉時候,呼叫bean的銷毀的方法(需要進行配置銷毀的方法)

(5)演示添加后置處理器的效果

? 1)創建類、實作介面BeanPostProcessor,創建后置處理器

MyBeanPost.java

package com.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPost implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第三步 在初始化之前執行的方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第五步 在初始化之后執行的方法");
        return bean;
    }
}


Orders.java

package com.bean;

public class Orders {


    private String oname;

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

    //1.無參構造
    public Orders() {
        System.out.println("第一步 執行無引數構造創建bean實體");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步 呼叫set方法設定屬性值");
    }

    //創建執行的初始化的方法
    private void initMethod(){
        System.out.println("第四步 執行初始化的方法");
    }

    //創建執行的銷毀的方法
    public void destroyMethod(){
        System.out.println("第七步 執行銷毀的方法");
    }
}

組態檔:

    <bean id="orders"  init-method="initMethod" destroy-method="destroyMethod">
        <property name="oname" value="https://www.cnblogs.com/DFshmily/p/手機"></property>
    </bean>

<!--    配置后置處理器-->
    <bean id="myBeanPost" ></bean>

Test:

package testdemo;

import com.bean.Orders;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class OrdersTest {
    @Test
    public void orderTset(){
//        ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("第六步 獲取創建bean實體物件");
        System.out.println(orders);


        //手動讓bean實體銷毀
        context.close();
    }
}


運行結果
第一步 執行無引數構造創建bean實體
第二步 呼叫set方法設定屬性值
第三步 在初始化之前執行的方法
第四步 執行初始化的方法
第五步 在初始化之后執行的方法
第六步 獲取創建bean實體物件
Orders{oname='手機'}
第七步 執行銷毀的方法

9.IOC操作Bean管理(xml自動裝配)

(1)什么是自動裝配

? 1)根據指定裝配規則(屬性名稱或者屬性型別),Spring自動匹配屬性值進行注入

(2)演示自動裝配程序

? 1)根據屬性名稱自動注入

配置:

<!--手動裝配-->
<!--    <bean id="emp" >-->
<!--        <property name="dept" ref="dept"></property>-->
<!--    </bean>-->
<!--    <bean id="dept" ></bean>-->

<!--    實作自動裝配
        bean標簽屬性autowire,配置自動裝配
        autowire屬性常用兩個值:
            byName根據屬性名稱注入,注入值bean的id值和類屬性名稱一樣
            byType根據屬性型別注入
-->
    <bean id="emp"  autowire="byName">
    </bean>
    <bean id="dept" ></bean>

    

Emp.java

package com.autowire;
//員工
public class Emp {

    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }
    public void test(){
        System.out.println(dept);
    }
}

Dept.java

package com.autowire;
//部門
public class Dept {
    @Override
    public String toString() {
        return "Dept{}";
    }
}

Test:

public class TestSpring {
    @Test
    public void test1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");
        Emp emp = context.getBean("emp",Emp.class);
        System.out.println(emp);
    }
}


運行結果:
 Emp{dept=Dept{}}

? 2)根據屬性型別自動注入

 <bean id="emp"  autowire="byType">
    </bean>
    <bean id="dept" ></bean>

10.IOC操作Bean管理(外部屬性檔案)

(1)直接配置資料庫資訊

? 1)配置Druid(德魯伊)連接池

? 2)引入Druid連接池jar包(下載地址:[Central Repository: com/alibaba/druid (maven.org)](https://druid.apache.org/downloads.html))

? 組態檔:

<!--    直接配置連接池-->
    <bean id="dataSource" >
        <property name="driverClassName" value="https://www.cnblogs.com/DFshmily/p/com.mysql.jdbc.Driver"></property>
        <property name="url" value="https://www.cnblogs.com/DFshmily/p/jdbc:mysql://localhost:3306/book"></property>
        <property name="username" value="https://www.cnblogs.com/DFshmily/p/root"></property>
        <property name="password" value=""></property>
    </bean>

(2)引入外部屬性檔案配置資料庫連接池

? 1)創建外部屬性檔案,properties格式檔案,寫資料庫資訊

prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/book
prop.username=root
prop.password=""

? 2)把外部properties屬性檔案引入到spring組態檔中

? ?引入context命名空間

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

? ?在spring組態檔使用標簽引入外部屬性檔案

<!--    引入外部屬性檔案-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
        <!--  配置連接池-->
        <bean id="dataSource" >
            <property name="driverClassName" value="https://www.cnblogs.com/DFshmily/p/${prop.driverClass}"></property>
            <property name="url" value="https://www.cnblogs.com/DFshmily/p/${prop.url}"></property>
            <property name="username" value="https://www.cnblogs.com/DFshmily/p/${prop.username}"></property>
            <property name="password" value="https://www.cnblogs.com/DFshmily/p/${prop.password}"></property>
        </bean>

11.IOC操作Bean管理(基于注解方式)

(1)什么是注解

? 1)注解是代碼特殊標記,格式:@注解名稱(屬性名稱=屬性值,屬性名稱=屬性值...)

? 2)使用注解,注解可以作用在類、方法、屬性上面

? 3)使用注解目的:簡化xml配置

(2)Spring針對Bean管理創建物件提供注解

? 1)@Component

? 2)@Service

? 3)@Controller

? 4)@Repository

? 上面四種注解功能是一樣的,都可以用來創建bean實體

(3)基于注解方式實作物件創建

? 1)引入依賴:spring-aop-5.3.9.jar

? 2)開啟組件掃描

<!--    開啟組件掃描
          如果掃描多個包,多個包用逗號隔開或者掃描包上層目錄
-->
    <context:component-scan base-package="com"></context:component-scan>

? 3)創建類,在類上面添加物件注解

package com.service;

import org.springframework.stereotype.Component;

/*
在注解里面value屬性值可以省略不寫
默認值是類名稱,首字母小寫
UserService-->userService
@Component可以替代為@Service,@Controller,@Repository,但在此一般習慣于用@Component
 */
@Component(value = "https://www.cnblogs.com/DFshmily/p/userService")//<bean id="userService" />
public class UserService {

    public void add(){
        System.out.println("service add...");
    }
}


(4)開啟組件掃描細節配置

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

<!--    開啟組件掃描
          如果掃描多個包,多個包用逗號隔開或者掃描包上層目錄
-->
    <context:component-scan base-package="com"></context:component-scan>

    
<!--    實體1:use-default-filters="false" 表示現在不使用默認filter,自己配置filter
             context:include-filter 表示掃描哪些內容
-->
    <context:component-scan base-package="com" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--    實體2:
            下面配置掃描包所有內容
            context:exclude-filter  設定哪些內容不進行掃描
-->
    <context:component-scan base-package="com">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

(5)基于注解方式實作屬性注入

? 1)@AutoWired :根據屬性型別進行自動裝配

? ①把service和dao物件創建,在service和dao類添加創建物件

? ②在service注入dao物件,在service類添加dao型別dao型別屬性,在屬性上面使用注解

UserService.java

package com.service;

import com.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    //定義dao型別屬性,不需要添加set方法,添加注入屬性注解
    @Autowired //根據型別進行注入
    private UserDao userDao;

    public void add(){
        System.out.println("service add...");
        userDao.add();
    }
}

UserDao.java

package com.dao;

public interface UserDao {
    public void add();
}

UserDaoImpl.java

package com.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void add(){
        System.out.println("dao add...");
    }
}

Test:

    @Test
    public void userTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
        UserService userService=context.getBean("userService", UserService.class);
        userService.add();
    }
}
運行結果;
service add...
dao add...

? 2)@Qualifier:根據屬性名稱進行注入

? @Qualifier注解的使用,和@AutoWired一起使用

UserService.java

@Service
public class UserService {

    //定義dao型別屬性,不需要添加set方法,添加注入屬性注解
    @Autowired //根據型別進行注入
    @Qualifier(value = "https://www.cnblogs.com/DFshmily/p/userDaoImpl1") //根據名稱進行注入
    private UserDao userDao;

    public void add(){
        System.out.println("service add...");
        userDao.add();
    }
}

UserDaoImpl.java

@Repository(value = "https://www.cnblogs.com/DFshmily/p/userDaoImpl1")
public class UserDaoImpl implements UserDao{
    @Override
    public void add(){
        System.out.println("dao add...");
    }
}

? 3)@Resource:可以根據型別注入,也可以根據名稱注入

  @Service
public class UserService {
	//@Resource()  //根據型別進行注入
    @Resource(name = "userDaoImpl1") //根據名稱進行注入
    private UserDao userDao;

    public void add(){
        System.out.println("service add...");
        userDao.add();
    }
}

? 4)@Value:注入普通型別屬性

  @Value(value = "https://www.cnblogs.com/DFshmily/p/DF")
    private String name;

(6)完全注解開發

? 1)創建配置類,替代xml組態檔

SpringConfig.java

package com.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration //作為配置類,替代xml組態檔
@ComponentScan(basePackages = {"com"})
public class SpringConfig {

}

? 2)撰寫測驗類

package com.testdemo;

import com.config.SpringConfig;
import com.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring {
    @Test
    public void userTest(){
        //加載配置類
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService=context.getBean("userService", UserService.class);
        userService.add();
    }
}


三、AOP

1.概念

(1)什么是AOP

? 1)面向切面編程(方面),利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率,

? 2)通俗描述:不通用修改源代碼方式,在主干功能里添加新功能

? 3)使用登錄例子說明AOP

image

### 2.AOP(底層原理)

(1)AOP底層使用動態代理

? 1)有兩種情況動態代理

? ①有介面情況,使用JDK動態代理

? ?創建介面實作類代理物件,增強類的方法

image

? ②沒有介面情況,使用CGLTB動態代理

? ?創建子類的代理物件,增強類的方法

image

3.AOP(JDK動態代理)

(1)使用JDK動態代理,使用proxy類里面的方法創建代理物件

java.lang.reflect 
Class Proxy
java.lang.Object 
java.lang.reflect.Proxy 

? 1)呼叫newProxyInstance方法

 static Object    newProxyInstance(ClassLoader loader, 類<?>[] interfaces, InvocationHandler h)  
    			  回傳指定的介面,將方法呼叫指定的呼叫處理程式的代理類的一個實體, 

? 方法中的三個引數:

ClassLoader loader 類加載器
類<?>[] interfaces 增強方法所在的類,這個類實作的介面,支持多個介面
InvocationHandler h 實作這個介面InvocationHandler,創建代理物件,寫增強的方法

(2)撰寫JDK動態代碼

? 1)創建介面,定義方法

UserDao.java

package com.spring;

public interface UserDao {
   public int add(int a,int b);
   public String update(String id);
}

? 2)創建介面實作類,實作方法

UserDaoImpl.java

package com.spring;

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

? 3)使用Proxy類創建介面代理物件

JDKProxy.java

package com.spring;

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

public class JDKProxy {
    public static void main(String[] args) {
        //第一種:創建介面實作類代理物件
        Class[] interfaces = {UserDao.class};
//        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                return null;
//            }
//        });
        //第二種:自定義名稱UserDaoProxy創建代理物件代碼
        UserDaoImpl userDao = new UserDaoImpl();
     UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
     int result = dao.add(1,2);
        System.out.println("result:"+result);
   }
}
//第二種:自定義名稱UserDaoProxy創建代理物件代碼
class  UserDaoProxy implements InvocationHandler{

    /*
    1.把創建的是誰的代理物件,把誰傳遞過來
    有參構造傳遞
     */
    private Object obj;
    public UserDaoProxy(Object obj){
        this.obj = obj;
    }

    //增強的邏輯
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //方法之前
        System.out.println("在方法之前執行..."+method.getName()+":傳遞的引數:"+ Arrays.toString(args));

        //被增強的方法執行
        Object res = method.invoke(obj, args);

        //方法之后
        System.out.println("在方法之后執行..."+obj);
        return res;
    }
}


運行結果:
在方法之前執行...add:傳遞的引數:[1, 2]
add方法執行了...
在方法之后執行...com.spring.UserDaoImpl@7ca48474
result:3

4.AOP(術語)

(1)連接點

? 類里面哪些方法可以被增強,這些方法稱為連接點

(2)切入點

? 實際被真正增強的方法,稱為切入點

(3)通知(增強)

? 1)實際增強的邏輯部分稱為通知(增強)

? 2)通知有多種型別

? ①前置通知

? ②后置通知

? ③環繞通知

? ④例外通知

? ⑤最終通知 finally

(4)切面

? 是動作,把通知應用到切入點的程序

5.AOP(準備)

(1)Spring框架一般基于AspectJ實作AOP操作

? 1)什么是AspectJ

AspectJ不是Spring組成部分,獨立AOP框架,一般把AspectJ和Spring框架一起使用,進行AOP操作

(2)基于AspectJ實作AOP操作

? 1)基于xml組態檔

? 2)基于注解方式實作(使用)

(3)在專案工程里面引入AOP相關依賴

image

(4)切入點運算式

? 1)切入點運算式的作用:知道對哪個類里面的哪個方法進行增強

? 2)語法結構:

? execution([權限修飾符] [回傳型別] [類全路徑] [方法名稱] [引數串列])

舉例1:對com.spring.UserDao類里面的add進行增強

? execution(* com.spring.UserDao.add(...))

舉例2:對com.spring.UserDao類里面的所有方法進行增強

? execution(* com.spring.UserDao.*(...))

舉例3:對com.spring包里面所有類,類里面的所有方法進行增強

? execution(* com.spring.*.*(...))

6.AOP操作(AspectJ注解)

(1)創建類,在類里面定義方法

User.java

package com.aop;

public class User {
    public void add(){
        System.out.println("add...");
    }
}

(2)創建增強類(撰寫增強邏輯)

(1)在增強類中創建方法,讓不同方法代表不同通知型別

UserProxy.java

package com.aop;
//增強的類
public class UserProxy {

    //前置通知
    public void before(){
        System.out.println("before...");
    }
}

(3)進行通知的配置

? 1)在spring組態檔中,開啟注解掃描

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                          http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd ">
    
<!--    開啟注解掃描-->
    <context:component-scan base-package="com.aop"></context:component-scan>
</beans>

? 2)使用注解創建User和UserProxy物件

User.java

//被增強的類
@Component
public class User {
    public void add(){
        System.out.println("add...");
    }
}

UserProxy.java

//增強的類
@Component
public class UserProxy {

    //前置通知
    public void before(){
        System.out.println("before...");
    }
}

? 3)在增強類上面添加注解@Aspect

UserProxy.java

//增強的類
@Component
@Aspect //生成代理物件
public class UserProxy {

    //前置通知
    public void before(){
        System.out.println("before...");
    }
}

? 4)在spring組態檔中開啟生成代理物件

xml:

<!--    開啟aspect生成代理物件-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

(4)配置不同型別的通知

? 1)在增強類的里面,在作為通知方法上面添加通知型別注解,使用切入點運算式配置

UserProxy.java

package com.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//增強的類
@Component
@Aspect //生成代理物件
public class UserProxy {

    //前置通知
    //@Before注解表示作為前置通知
    @Before(value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void before(){
        System.out.println("before...");
    }

    //最終通知
    @After(value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void after(){
        System.out.println("after...");
    }


    //后置通知(回傳通知)
    @AfterReturning(value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning...");
    }


    //例外通知
    @AfterThrowing (value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing...");
    }

    //環繞通知
    @Around(value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("環繞之前...");

        //被增強的方法執行
        proceedingJoinPoint.proceed();

        System.out.println("環繞之后...");
    }
}



Test:

package com.testdemo;

import com.aop.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {
    @Test
    public void testAop(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        User user = context.getBean("user", User.class);
        user.add();
    }
}

運行結果:
    
環繞之前...
before...
add...
afterReturning...
after...
環繞之后...

(5)相同的切入點抽取

    //相同切入點抽取
    @Pointcut(value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void pointcut(){
    }

    //前置通知
    //@Before注解表示作為前置通知
    @Before(value = "https://www.cnblogs.com/DFshmily/p/pointcut")
    public void before(){
        System.out.println("before...");
    }

(6)有多個增強類多個同一方法進行增強,設定增強類優先級

? 1)在增強類上面添加注解@Order(數字型別值),數字型別值越小優先級越高

@Component
@Aspect
@Order(1)
public class PersonProxy {

    @Before(value = "https://www.cnblogs.com/DFshmily/p/execution(* com.aop.User.add(..))")
    public void afterReturning(){
        System.out.println("Person Before...");
    }
}

(7)完全使用注解開發

? 1)創建配置類,不需要創建xml組態檔

@Configuration
@ComponentScan(basePackages ="com.aop" )
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {

}

7.AOP操作(AspectJ組態檔)

(1)創建兩個類,增強類和被增強類,創建方法

Book.java

package com.aopxml;
//被增強類
public class Book {
    public void buy(){
        System.out.println("buy...");
    }
}

BookProxy.java

package com.aopxml;
//增強類
public class BookProxy {
    public void before(){
        System.out.println("before...");
    }
}

(2)在spring組態檔中創建兩個類物件

<?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="book" ></bean>
    <bean id="bookProxy" ></bean>
</beans>

(3)在spring組態檔中配置切入點

<!--    配置aop增強-->
    <aopa:config>
<!--        切入點-->
        <aopa:pointcut id="point" expression="execution(* com.aopxml.Book.buy(..))"/>
<!--        配置切面-->
        <aopa:aspect ref="bookProxy">
<!--            配置增強作用在具體的方法上-->
            <aopa:before method="before" pointcut-ref="point"/>
        </aopa:aspect>
    </aopa:config>

Test:

    @Test
    public void testAop1(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        Book book = context.getBean("book", Book.class);
        book.buy();
    }

運行結果:
    
before...
buy...

四、JdbcTemplate

1.什么是JdbcTemplate

(1)Spring框架對JDBC進行封裝,使用JdbcTemplate方便實作對資料庫操作

2.準備作業

(1)引入相關jar包

image

(2)在spring組態檔中配置資料庫連接池

<!--    資料庫連接池-->
    <bean id="dataSource"  destroy-method="close">
        <property name="url" value="https://www.cnblogs.com/DFshmily/p/jdbc:mysql://localhost:3306/book"></property>
        <property name="username" value="https://www.cnblogs.com/DFshmily/p/root"></property>
        <property name="password" value=""></property>
        <property name="driverClassName" value="https://www.cnblogs.com/DFshmily/p/com.mysql.jdbc.Driver"></property>
    </bean>

(3)配置JdbcTemplate物件,注入DataSource

<!--    JdbcTemplate物件-->
    <bean id="jdbcTemplate" >
<!--        注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

(4)創建sercvice類,創建dao類,在dao注入jdbcTemplate物件

? ?組態檔

<!--    開啟組件掃描-->
    <context:component-scan base-package="com"></context:component-scan>

? ?service

package com.service;

import com.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    //注入dao
    @Autowired
    private BookDao bookDao;
}

?Dao

package com.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao{

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

}

3.JdbcTemplate操作資料庫(添加)

(1)對應資料庫表創建物體類

User.java

package com.entity;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String email;

    public Integer getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public String getEmail() {
        return email;
    }
}

(2)撰寫service和dao

? 1)在dao進行資料庫添加操作

? 2)呼叫JdbcTemplate物件里面update方法實作添加操作

update(String sql,Object...args)

有兩個引數:

?第一個引數:sql陳述句

?第二個引數:可變引數,設定sql陳述句值

BookDaoImpl.java

package com.dao;

import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;


@Repository
public class BookDaoImpl implements BookDao{

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //添加的方法
    @Override
    public void add(Book book) {
        //1.創建sql陳述句
        String sql = "insert into t_user values(?,?,?)";
        //2.呼叫方法實作
       int update = jdbcTemplate.update(sql,book.getId(),book.getUsername(),book.getPassword(),book.getEmail());
        System.out.println(update);
    }
}

BookService.java

package com.service;

import com.dao.BookDao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;



@Service
public class BookService {

    //注入dao
    @Autowired
    private BookDao bookDao;

    //添加的方法
    public void addBook(Book book){
        bookDao.add(book);
    }

}

BookDao.java

package com.dao;


import com.entity.Book;

public interface BookDao {
    //添加的方法
    void add(Book book);
}

Book.java

package com.entity;

public class Book {
    private String id;
    private String username;
    private String password;
    private String email;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public String getEmail() {
        return email;
    }
}

(3)測驗類

package com.test;

import com.entity.Book;
import com.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TsetBook {

    @Test
    public void testJdbcTemplate(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService",BookService.class);
        Book book = new Book();
        book.setId("7");
        book.setUsername("c");
        book.setPassword("c");
        book.setEmail("[email protected]");
        bookService.addBook(book);
    }
}

運行結果:
10月 02, 2022 7:44:51 下午 com.alibaba.druid.pool.DruidDataSource info
資訊: {dataSource-1} inited
1

4.JdbcTemplate操作資料庫(修改和洗掉)

BookService.java

package com.service;

import com.dao.BookDao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;



@Service
public class BookService {

    //注入dao
    @Autowired
    private BookDao bookDao;

    //添加的方法
    public void addBook(Book book){
        bookDao.add(book);
    }


    //修改的方法
    public void updateBook(Book book){
        bookDao.update(book);
    }

    //洗掉的方法
    public void deleteBook(String id){
        bookDao.delete(id);
    }
}

BookDao.java

package com.dao;


import com.entity.Book;

public interface BookDao {
    //添加的方法
    void add(Book book);

    void update(Book book);

    void delete(String id);


}

BookDaoImpl.java

package com.dao;

import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;


@Repository
public class BookDaoImpl implements BookDao{

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //添加的方法
    @Override
    public void add(Book book) {
        //1.創建sql陳述句
        String sql = "insert into t_user values(?,?,?,?)";
        //2.呼叫方法實作
       int update = jdbcTemplate.update(sql,book.getId(),book.getUsername(),book.getPassword(),book.getEmail());
        System.out.println(update);
    }

    //修改
    @Override
    public void update(Book book) {
        String sql = "update t_user set username=?,password=?,email=?,where id=?";
        Object[] args = {book.getUsername(),book.getPassword(), book.getEmail(),book.getId()};
        int update = jdbcTemplate.update(sql,args);
        System.out.println(update);
    }

    //洗掉
    @Override
    public void delete(String id) {
        String sql = "delete from t_user where id=?";
        int update = jdbcTemplate.update(sql,id);
        System.out.println(update);
    }
}

Test:

package com.test;

import com.entity.Book;
import com.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TsetBook {

    @Test
    public void testJdbcTemplate(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService",BookService.class);

        //添加
//        Book book = new Book();
//        book.setId("7");
//        book.setUsername("c");
//        book.setPassword("c");
//        book.setEmail("[email protected]");
//        bookService.addBook(book);

        //修改
//        Book book = new Book();
//        book.setId("7");
//        book.setUsername("python");
//        book.setPassword("p");
//        book.setEmail("[email protected]");
//        bookService.updateBook(book);
//

        //洗掉
        bookService.deleteBook("7");
    }
}
運行結果:
資訊: {dataSource-1} inited
1

5.JdbcTempalte操作資料庫(查詢回傳某個值)

(1)查詢表里面有多少條記錄,回傳是某個值

(2)使用JdbcTemplate實作查詢回傳某個值代碼

queryForObject(String sql,Class<T> requiredType)

有兩個引數:

?第一個引數:sql陳述句

?第二個引數:回傳型別Class

BookDaoImpl.java

package com.dao;

import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;


@Repository
public class BookDaoImpl implements BookDao{

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    //添加的方法
    @Override
    public void add(Book book) {
        //1.創建sql陳述句
        String sql = "insert into t_user values(?,?,?,?)";
        //2.呼叫方法實作
       int update = jdbcTemplate.update(sql,book.getId(),book.getUsername(),book.getPassword(),book.getEmail());
        System.out.println(update);
    }

    //修改
    @Override
    public void update(Book book) {
        String sql = "update t_user set username=?,password=?,email=? where id=?";
        Object[] args = {book.getUsername(),book.getPassword(), book.getEmail(),book.getId()};
        int update = jdbcTemplate.update(sql,args);
        System.out.println(update);
    }

    //洗掉
    @Override
    public void delete(String id) {
        String sql = "delete from t_user where id=?";
        int update = jdbcTemplate.update(sql,id);
        System.out.println(update);
    }

    //查詢表記錄數
    @Override
    public int selectCount() {

        String sql = "select count(*) from t_user";
        Integer count = jdbcTemplate.queryForObject(sql,Integer.class);
        return count;
    }
}

BookService.java

package com.service;

import com.dao.BookDao;
import com.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;



@Service
public class BookService {

    //注入dao
    @Autowired
    private BookDao bookDao;

    //添加的方法
    public void addBook(Book book){
        bookDao.add(book);
    }


    //修改的方法
    public void updateBook(Book book){
        bookDao.update(book);
    }

    //洗掉的方法
    public void deleteBook(String id){
        bookDao.delete(id);
    }

    //查詢表記錄數
    public int findCount() {
      return bookDao.selectCount();
    }
}

BookDao.java

package com.dao;


import com.entity.Book;

public interface BookDao {
    //添加的方法
    void add(Book book);

    //修改的方法
    void update(Book book);

    //洗掉的方法
    void delete(String id);

    //查詢表記錄數
    int selectCount();

}

Test:

package com.test;

import com.entity.Book;
import com.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TsetBook {

    @Test
    public void testJdbcTemplate(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService",BookService.class);

        //添加
//        Book book = new Book();
//        book.setId("7");
//        book.setUsername("c");
//        book.setPassword("c");
//        book.setEmail("[email protected]");
//        bookService.addBook(book);

        //修改
//        Book book = new Book();
//        book.setId("7");
//        book.setUsername("python");
//        book.setPassword("p");
//        book.setEmail("[email protected]");
//        bookService.updateBook(book);
//

        //洗掉
        //bookService.deleteBook("7");

        //查詢回傳某個值
        int count = bookService.findCount();
        System.out.println(count);
    }
}

運行結果:
資訊: {dataSource-1} inited
5

6.JdbcTemplate操作資料庫(查詢回傳物件)

(1)場景:查詢圖書詳情

(2)JdbcTemplate實作查詢回傳物件

queryForObject(String sql,RowMapper<T> rowMapper,Object... args)

有三個引數:

?第一個引數:sql陳述句

?第二個引數:RowMapper是介面,回傳不同型別資料,使用這個介面里面實作類完成資料的封裝

?第三個引數:sql陳述句值

BookDaoImpl.java

    //查詢回傳物件
    @Override
    public Book findBookInfo(String id) {
        String sql = "select * from t_user where id=?";
        //呼叫方法
        Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
        return book;
    }

BookService.java

//查詢回傳物件
    public Book findOne(String id){
        return bookDao.findBookInfo(id);
    }

BookDao.java

 //查詢回傳物件
    Book findBookInfo(String id);

Test:

     //查詢回傳物件
        Book book =bookService.findOne("1");
        System.out.println(book);


運行結果: 
資訊: {dataSource-1} inited
Book{id='1', username='admin', password='123', email='[email protected]'}

7.JdbcTemplate操作資料庫(查詢回傳集合)

(1)場景:查詢圖書串列分頁

(2)呼叫JdbcTemplate方法實作查詢回傳集合

query(String sql,RowMapper<T> rowMapper,Object... args)

有三個引數:

?第一個引數:sql陳述句

?第二個引數:RowMapper是介面,回傳不同型別資料,使用這個介面里面實作類完成資料的封裝

?第三個引數:sql陳述句值

BookDaoImpl.java

  //查詢回傳集合
    @Override
    public List<Book> findAllBook() {
        String sql = "select * from t_user";
        //呼叫方法
        List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
        return bookList;
    }

BookService.java

 //查詢回傳集合
    public List<Book> findAll(){
        return bookDao.findAllBook();
    }

BookDao.java

 //查詢回傳集合
    List<Book> findAllBook();

Test:

   //查詢回傳集合
        List<Book> all = bookService.findAll();
        System.out.println(all);
    }
運行結果:
資訊: {dataSource-1} inited
[Book{id='1', username='admin', password='123', email='[email protected]'}, Book{id='2', username='dd', password='123', email='[email protected]'}, Book{id='4', username='dd1', password='123', email='[email protected]'}, Book{id='5', username='hh', password='123', email='[email protected]'}, Book{id='6', username='java', password='j', email='[email protected]'}]

8.JdbcTemplate操作資料庫(批量操作)

(1)批量操作:操作表里面的多條資料

(2)JdbcTemplate實作批量添加操作

batchUpdate(String sql,List<Object[]> batchArgs)

有二個引數:

?第一個引數:sql陳述句

?第二個引數:List集合,添加多條記錄數

BookDaoImpl.java

 //批量添加
    @Override
    public void batchAddBook(List<Object[]> batchArgs) {
        String sql = "insert into t_user values(?,?,?,?)";
        int[] ints = jdbcTemplate.batchUpdate(sql,batchArgs);
        System.out.println(Arrays.toString(ints));
    }

BookService.java

 //批量添加
    public void batchAdd(List<Object[]> batchArgs){
        bookDao.batchAddBook(batchArgs);
    }

BookDao.java

//批量添加
    public void batchAddBook(List<Object[]> batchArgs);

Test:

   //批量添加
       List<Object[]> batchArgs = new ArrayList<>();
       Object[] o1 = {"7","python","p","[email protected]"};
       Object[] o2 = {"8","c#","cc","[email protected]"};
       batchArgs.add(o1);
       batchArgs.add(o2);
       //呼叫批量添加
        bookService.batchAdd(batchArgs);
   
運行結果:
資訊: {dataSource-1} inited
[1, 1]

(3)JdbcTemplate實作批量修改操作

BookDaoImpl.java

 //批量修改
    @Override
    public void batchUpdateBook(List<Object[]> batchArgs) {
        String sql = "update t_user set username=?,password=?,email=? where id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }

BookService.java

//批量修改
    public void batchUpdate(List<Object[]> batchArgs){
        bookDao.batchUpdateBook(batchArgs);
    }

BookDao.java

 //批量修改
    void batchUpdateBook(List<Object[]> batchArgs);

Test:

        //批量修改
        List<Object[]> batchArgs = new ArrayList<>();
        Object[] o1 = {"ddd","d","[email protected]","7"};
        Object[] o2 = {"fff","f","[email protected]","8"};
        batchArgs.add(o1);
        batchArgs.add(o2);

        //呼叫批量修改
        bookService.batchUpdate(batchArgs);
   
運行結果:
資訊: {dataSource-1} inited
[1, 1]

(4)JdbcTemplate操作資料庫(批量洗掉)

BookDaoImpl.java

//批量洗掉
    @Override
    public void batchDeleteBook(List<Object[]> batchArgs) {
        String sql = "delete from t_user where id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }

BookService.java

 //批量修改
    public void batchDelete(List<Object[]> batchArgs){
        bookDao.batchDeleteBook(batchArgs);
    }

BookDao.java

//批量洗掉
    void batchDeleteBook(List<Object[]> batchArgs);

Test:

        //批量洗掉
        List<Object[]> batchArgs = new ArrayList<>();
        Object[] o1 = {"2"};
        Object[] o2 = {"4"};
        batchArgs.add(o1);
        batchArgs.add(o2);

        //呼叫批量洗掉
        bookService.batchDelete(batchArgs);

運行結果:
資訊: {dataSource-1} inited
[1, 1]

五、事物管理

1.事務概念

(1)什么是事務

? 1)事務是資料庫操作最基本單元,邏輯上一組操作,要么都成功,如果有一個失敗所有操作都失敗

? 2)典型場景:銀行轉賬

(2)事務四個特性(ACID)

? 1)原子性

? 2)一致性

? 3)隔離性

? 4)持久性

2.事務操作(搭建事務操作環境)

image

(1)創建資料庫表,添加記錄

image

(2)創建service,搭建dao,完成物件創建和注入關系

? 1)service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DataSource

? UserService.java

package com.service;

import com.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    //注入aop
    @Autowired
    private UserDao userDao;
}

UserDaoImpl.java

package com.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

}

(3)在dao創建兩個方法:多錢和少錢的方法,在service創建(轉賬的方法)

UserService.java

package com.service;

import com.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    //注入aop
    @Autowired
    private UserDao userDao;

    //轉賬的方法
    public void accountMoney(){
        //dd少100
        userDao.reduceMoney();

        //df多100
        userDao.addMoney();
    }
}

UserDao.java

package com.dao;

public interface UserDao {
    //多錢
    public void addMoney();
    //少錢
    public void reduceMoney();
}

UserDaoImpl.java

package com.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //多錢
    @Override
    public void addMoney() {
        String sql = "update count set money=money+? where username=?";
        JdbcTemplate.update(sql,100,"df");
    }

    //少錢
    @Override
    public void reduceMoney() {
        String sql = "update count set money=money-? where username=?";
        JdbcTemplate.update(sql,100,"dd");
    }
}

Test:

package com.test;

import com.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBook {
    @Test
    public void TsetUser(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        UserService userService = context.getBean("userservice",UserService.class);
        userService.accountMoney();
    }
}

六、Spring 5 新特性

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/510849.html

標籤:Java

上一篇:AUSTOj4

下一篇:Redis詳解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more