Springboot中sharding-jdbc的API模式并使用自定义算法

Springboot中sharding-jdbc的API模式并使用自定义算法

可配合AbstractRoutingData使用切换数据源

程序用到了AbstractRoutingData来切换数据源(数据源是自定义的格式编写并没有用springboot的自动装配的格式写),但是又用到sharding-jdbc进行分库分页,如果直接引用sharding-jdbc-spring-boot-starter会自动装配它自己默认的数据源dataSource,导致我们自己写的数据源失效。所以我们需要用API的模式把sharding-jdbc的数据源dataSource放入我们自己的写的AbstractRoutingData里面来。


POM文件添加


<dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core</artifactId>
            <version>5.1.2</version>
 </dependency>

自定义的数据库信息格式

在这里插入图片描述


使用AbstractRoutingData切换数据源


public class DynamicDataSource extends AbstractRoutingDataSource {
	private static final Logger logger = Logger.getLogger(DynamicDataSource.class);
 
    private static DynamicDataSource dynamicDataSource;
  
    private final Map<Object, Object> targetDataSources = new HashMap();
    
    private static final ThreadLocal<String> dataSourceName = new ThreadLocal();

    public DynamicDataSource() {
    }

    public static DynamicDataSource getInstance() {
        if (dynamicDataSource == null) {
            synchronized(DynamicDataSource.class) {
                if (dynamicDataSource == null) {
                    dynamicDataSource = new DynamicDataSource();
                }
            }
        }
        return dynamicDataSource;
    }
	/**
	*determineCurrentLookupKey() 方法决定使用哪个数据源
	*/
    protected Object determineCurrentLookupKey() {
        return (String)dataSourceName.get();
    }


    public void setTargetDataSources(Map<String, DataSource> targetDataSources) {
    	//设置默认数据源
    	//super.setDefaultTargetDataSource(targetDataSources.get("default"));
        this.targetDataSources.putAll(targetDataSources);
        //设置数据源
        super.setTargetDataSources(this.targetDataSources);
        super.afterPropertiesSet();
    }

    public Map<Object, Object> getTargetDataSources() {
        return this.targetDataSources;
    }

    public void removeDataSource(String code) {
        if (this.targetDataSources.get(code) != null) {
            this.targetDataSources.remove(code);
        }
        //重新设置数据源
        super.setTargetDataSources(this.targetDataSources);
        super.afterPropertiesSet();
    }
    
    public static void setDataSource(String datasource) {
        logger.info("切换数据源为:"+datasource);
        dataSourceName.set(datasource);
    }
    
	public static void clear() {
        dataSourceName.remove();
    }

}
  • 数据源是自定义的,要禁用springboot的数据源自动装配配置,启动类上加上
 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

写入自己的自定义数据源


@Configuration
public class ShardingDataSourceConfig{
    Logger logger = Logger.getLogger(ShardingDataSourceConfig.class);

    @Primary
    @Bean
    public DataSource shardingdataSource() throws SQLException, IOException {
    	//获取AbstractRoutingData对象
        DynamicDataSource chooseDataSource = DynamicDataSource.getInstance();
        //获取自己配置文件上的普通数据源,该方法忽略展示,key为数据库的名字,value为数据源
        Map<String, DataSource> targetDataSources = this.getTargetDataSources();
        /*生成数据源的样式,使用DruidDataSource,POM文件记得加入,也可以使用其他数据源
   		DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(stringStringMap.get("driverClassName"));
        dataSource.setUrl(stringStringMap.get("url"));
        dataSource.setUsername(stringStringMap.get("username"));
        dataSource.setPassword(stringStringMap.get("password"));
        */
        //设置默认的数据源,必须保证Map里面有该值,可以放在DynamicDataSource里面再设置
        chooseDataSource.setDefaultTargetDataSource(targetDataSources.get("default"));
        //添加自己的sharding-jdbc数据源
        //分库分表数据源
        DataSource shardingDataSource = ShardingDataBaseConfiguration.getDataSource(shardingPrefixss);
    	targetDataSources.put("shardingDT",shardingDataSource);
        //只分表数据源
        DataSource dataSource = ShardingTableConfiguration.getDataSource(sourceDataBase);
            targetDataSources.put("shardingT",dataSource);
        }
        chooseDataSource.setTargetDataSources(targetDataSources);
        return chooseDataSource;
    }
}

获取配置文件辅助类,网上很多方法,这里使用的是继承PropertyPlaceholderConfigurer类


public class PropertyPlaceholder extends PropertyPlaceholderConfigurer {

    private static Map<String,String> propertyMap;

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
        super.processProperties(beanFactoryToProcess, props);
        propertyMap = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            String keyStr = key.toString();
            String value = props.getProperty(keyStr);
            propertyMap.put(keyStr, value);
        }
    }

    //自定义一个方法,即根据key拿属性值,方便java代码中取属性值
    public static String getProperty(String name) {
        return propertyMap.get(name);
    }
}

定义自己的sharding分片规则,并返回sharding的数据源.

分库分表配置

public class ShardingDataBaseConfiguration {
    /**
     * 创建数据源
     */
    private static Map<String, DataSource> createDataSourceMap(List<String> datasourceNames){
        Map<String, DataSource> dataSourceMap=new HashMap<>();
        for (int i = 0; i < datasourceNames.size(); i++) {
            Map<String, String> stringStringMap = DataBaseInfoUtil.getDataBaseInformation().get(datasourceNames.get(i));
            if (ObjectUtil.isNull(stringStringMap)){
                return null;
            }
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(stringStringMap.get("driverClassName"));
            dataSource.setUrl(stringStringMap.get("url"));
            dataSource.setUsername(stringStringMap.get("username"));
            dataSource.setPassword(stringStringMap.get("password"));
            dataSourceMap.put("ds_"+datasourceNames.get(i), dataSource);
        }
        return dataSourceMap;
    }

    /**
     * 分库分表设置
     * create_time为分库的字段,按create_time字段的值来进行分库计算
     * HashModShardingAlgorithm.class.getName()是算法名字,可随便写,需要和分表配置的算法名字对应上就行
     * MY_HASH_MOD、MY_COMPLEX_INLINE、DATABASE_INLINE自定义算法的名字,最重要的地方,必须和自定义算法类中返回的名字一致,就是getType()返回的值,名字可以随意取
     * */
    private static ShardingRuleConfiguration createShardingRuleConfiguration() {
        ShardingRuleConfiguration configuration = new ShardingRuleConfiguration();
        configuration.getTables().add(getWlbTableRuleConfiguration());
        configuration.getTables().add(getWiorpTableRuleConfiguration());
        //设置分库的规则,按年份分库
        configuration.setDefaultDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("create_time", PreciseDatabaseShardingAlgorithm.class.getName()));
        configuration.getShardingAlgorithms().put(HashModShardingAlgorithm.class.getName(),new ShardingSphereAlgorithmConfiguration("MY_HASH_MOD",new Properties()));
        configuration.getShardingAlgorithms().put(ComplexShardingAlgorithm.class.getName(),new ShardingSphereAlgorithmConfiguration("MY_COMPLEX_INLINE",new Properties()));
        configuration.getShardingAlgorithms().put(PreciseDatabaseShardingAlgorithm.class.getName(),new ShardingSphereAlgorithmConfiguration("DATABASE_INLINE",new Properties()));
        return configuration;
    }



    /**
     * 制定my_test表分片规则
     * my_test为逻辑表名,my_test_0,my_test_1....my_test_9为实际数据库的表名,就是把数据分到这0-9的表中
     * ds_${2020..2022} 为实际数据源的名字:ds_2020,ds_2021,ds_2022,写法${..},{}里面可以进行运算,例如ds_${id % 2}
     * sub_base为my_test表的分表字段,就是my_test表的分表规则按sub_base来区分
     * HashModShardingAlgorithm.class.getName(),这个是算法的名字可以随意起,对应configuration.getShardingAlgorithms().put()中key的值,写上自己自定义的类名好容易确认区分,sharding-jdbc也有自己默认定义好的分片算法
     * 如果使用ds_${id % 2}这种在{}进行运算的,可以不写setTableShardingStrategy
     * */
    private static ShardingTableRuleConfiguration getWlbTableRuleConfiguration(){
        ShardingTableRuleConfiguration tableRule=new ShardingTableRuleConfiguration("my_test","ds_${2020..2022}.my_test_${0..9}");
        tableRule.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("id","snowflake"));
        tableRule.setTableShardingStrategy(new StandardShardingStrategyConfiguration("sub_base",HashModShardingAlgorithm.class.getName()));
        return tableRule;
    }

    /**
     * 制定my_test2表分库分片规则
     * */
    private static ShardingTableRuleConfiguration getWiorpTableRuleConfiguration(){
        ShardingTableRuleConfiguration tableRule=new ShardingTableRuleConfiguration("my_test2","ds_${2020..2022}.my_test2_${0..9}");
        tableRule.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("id","snowflake"));
        tableRule.setTableShardingStrategy(new ComplexShardingStrategyConfiguration("code,name,sex,age", ComplexShardingAlgorithm.class.getName()));
        return tableRule;
    }


    public static DataSource getDataSource(List<String> datasourceNames) throws SQLException {
        // 其他配置
        Properties properties = new Properties();
        //控制台日志展示sharding-jdbc的sql
        properties.put("sql-show","true");
        return ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(datasourceNames),
                Collections.singleton(createShardingRuleConfiguration()),properties);
    }


}

仅分表配置

public class ShardingTableConfiguration {
    /**
     * 创建数据源
     */
    private static Map<String, DataSource> createDataSourceMap(List<String> datasourceNames){
        Map<String, DataSource> dataSourceMap=new HashMap<>();
        for (int i = 0; i < datasourceNames.size(); i++) {
            Map<String, String> stringStringMap = DataBaseInfoUtil.getDataBaseInformation().get(datasourceNames.get(i));
            if (ObjectUtil.isNull(stringStringMap)){
                return null;
            }
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(stringStringMap.get("driverClassName"));
            dataSource.setUrl(stringStringMap.get("url"));
            dataSource.setUsername(stringStringMap.get("username"));
            dataSource.setPassword(stringStringMap.get("password"));
            dataSourceMap.put("ds0", dataSource);
        }
        return dataSourceMap;
    }

    /**
     * 分表设置
     */
    private static ShardingRuleConfiguration createShardingRuleConfigurationOnlyTable() {
        ShardingRuleConfiguration configuration = new ShardingRuleConfiguration();
        configuration.getTables().add(getWlbTableRuleConfiguration());
        configuration.getTables().add(getWiorpTableRuleConfiguration());
        configuration.getShardingAlgorithms().put(HashModShardingAlgorithm.class.getName(),new ShardingSphereAlgorithmConfiguration("MY_HASH_MOD",new Properties()));
        configuration.getShardingAlgorithms().put(ComplexShardingAlgorithm.class.getName(),new ShardingSphereAlgorithmConfiguration("MY_COMPLEX_INLINE",new Properties()));
        return configuration;
    }


    /**
     * 制定my_test3表分片规则
     */
    private static ShardingTableRuleConfiguration getWlbTableRuleConfiguration(){
        ShardingTableRuleConfiguration tableRule=new ShardingTableRuleConfiguration("my_test3","ds0.my_test3_${0..9}");
        tableRule.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("id","snowflake"));
        tableRule.setTableShardingStrategy(new StandardShardingStrategyConfiguration("box_batch",HashModShardingAlgorithm.class.getName()));
        return tableRule;
    }

    /**
     * 制定my_test4表分库分片规则
     */
    private static ShardingTableRuleConfiguration getWiorpTableRuleConfiguration(){
        ShardingTableRuleConfiguration tableRule=new ShardingTableRuleConfiguration("my_test4","ds0.my_test4_${0..9}");
        tableRule.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("id","snowflake"));
        tableRule.setTableShardingStrategy(new ComplexShardingStrategyConfiguration("code,name,sex,age", ComplexShardingAlgorithm.class.getName()));
        return tableRule;
    }


    public static DataSource getDataSource(String datasourceNames) throws SQLException {
        // 其他配置
        Properties properties = new Properties();
        properties.put("sql-show","true");
        return ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(new ArrayList<String>(){{add(datasourceNames);}}),
                Collections.singleton(createShardingRuleConfigurationOnlyTable()),properties);
    }


}

自定义分库分片算法

标准分片算法

public final class HashModShardingAlgorithm implements StandardShardingAlgorithm<String> {
    
   
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> shardingValue) {
        if(StringUtil.isEmpty(shardingValue.getValue())){
            throw new CommonException("precise sharding value is null");
        }
        String suffix = String.valueOf(Math.abs((long) shardingValue.hashCode())) % collection.size());
        for (String tableName : collection) {
            if (tableName.endsWith(suffix)) {
                return tableName;
            }
        }
        throw new UnsupportedOperationException();
    }


    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
        return collection;
    }

    @Override
    public Properties getProps() {
        return null;
    }

    @Override
    public void init(Properties properties) {

    }

	//返回的算法名字
    public String getType() {
        return "MY_HASH_MOD";
    }
}

复合字段算法

public class ComplexShardingAlgorithm implements ComplexKeysShardingAlgorithm {

    @Override
    public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
        // 返回真实表名集合
        List<String> tableNameList = new ArrayList<>();

        // 逻辑表名
        String logicTableName = complexKeysShardingValue.getLogicTableName();


        // 获取分片键的值,算法自己定义
        Collection<String> factoryCodes = (Collection<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("code");
        Collection<String> workshopCodes = (Collection<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("name");
        Collection<String> storehouseCodes = (Collection<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("sex");
        Collection<String> materialNos = (Collection<String>) complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("age");

        if (ListUtil.isEmpty(factoryCodes)
                || ListUtil.isEmpty(workshopCodes)
                || ListUtil.isEmpty(storehouseCodes)
                || ListUtil.isEmpty(materialNos)) {//分片键缺任何一个字段均返回全部表
            for (String tableName : (Collection<String>) collection) {
                tableNameList.add(tableName);
            }
            return tableNameList;//返回全部
        }

        // 获取真实表名
        String realName = getTabel(factoryCodes) + getTabel(workshopCodes)+ getTabel(storehouseCodes);
        for (String materialNo : materialNos) {
            long abs = Math.abs((long) (realName + materialNo).hashCode());
            String tableSuffix = String.valueOf(abs % 10);
            for (String tableName : (Collection<String>) collection) {
                if (tableName.endsWith("_" + tableSuffix)) {
                    tableNameList.add(tableName);
                }
            }
        }
        return tableNameList;
    }

    /**
     * 获取表名
     *
     * @param codes
     * @return
     */
    private String getTabel(Collection<String> names) {
        Optional<String> name = names.stream().findFirst();
        if (name.isPresent()) {
            return name.get();
        }
        return "";
    }

    @Override
    public Properties getProps() {
        return null;
    }

    @Override
    public void init(Properties properties) {

    }
    
	//返回的算法名字
    public String getType() {
        return "MY_COMPLEX_INLINE";
    }
}

分库算法

public class PreciseDatabaseShardingAlgorithm implements StandardShardingAlgorithm<LocalDateTime> {
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<LocalDateTime> preciseShardingValue) {
        //对于库的分片collection存放的是所有的库的列表,这里代表ds_2020~dataSource_2022
        //配置的分片的sharding-column对应的值
        LocalDateTime year = preciseShardingValue.getValue();
        if(ObjectUtil.isNull(year)){
            throw new UnsupportedOperationException("preciseShardingValue is null");
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy");
        //按年路由
        for (String each : collection) {
            String value = formatter.format(year);//获取到年份
            if(each.endsWith(value)){
                // //这里返回回去的就是最终需要查询的库名
                return each;
            }
        }
        throw new UnsupportedOperationException();
    }


    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<LocalDateTime> rangeShardingValue) {
        return collection;
    }

    @Override
    public Properties getProps() {
        return null;
    }

    @Override
    public void init(Properties properties) {

    }

	//返回算法的名字
    public String getType() {
        return "DATABASE_INLINE";
    }
}

自定义算法重点

SPI机制
需要在resources下面写上
META-INF.services.org.apache.shardingsphere.sharding.spi.ShardingAlgorithm
在这里插入图片描述
里面的内容写上算法的路径
在这里插入图片描述

使用
在需要切换数据源的地方设置数据源DynamicDataSource.setDataSource(自定义的数据源名字),使用完后记得remove,切换为默认数据源避免出问题
事务
必须在切换数据源后才开启事务,单事务,在事务中切换数据源是不生效的

PS:写出来仅仅为了自己后面能重新看到,如果有好的方法也可以告诉我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/87271.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序+Springboot校园二手商城系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、目前专注于大学生项目实战开发,讲解,毕业答疑辅导✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3…

【Java 高阶】一文精通 Spring MVC - 数据格式化器(六)

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

接口经典题目

​ White graces&#xff1a;个人主页 &#x1f649;专栏推荐:《Java入门知识》&#x1f649; &#x1f649; 内容推荐:继承与组合&#xff1a;代码复用的两种策略&#x1f649; &#x1f439;今日诗词:人似秋鸿来有信&#xff0c;事如春梦了无痕。&#x1f439; 目录 &…

供应链安全和第三方风险管理:讨论如何应对供应链中的安全风险,以及评估和管理第三方合作伙伴可能带来的威胁

第一章&#xff1a;引言 在当今数字化时代&#xff0c;供应链的安全性越来越受到重视。企业的成功不仅仅依赖于产品和服务的质量&#xff0c;还取决于供应链中的安全性。然而&#xff0c;随着供应链越来越复杂&#xff0c;第三方合作伙伴的参与也带来了一系列安全风险。本文将…

RPC和HTTP协议

RPC 全称&#xff08;Remote Procedure Call&#xff09;&#xff0c;它是一种针对跨进程或者跨网络节点的应用之间的远程过程调用协议。 它的核心目标是&#xff0c;让开发人员在进行远程方法调用的时候&#xff0c;就像调用本地方法一样&#xff0c;不需要额外为了完成这个交…

[JavaWeb]【十】web后端开发-SpringBootWeb案例(配置文件)

目录 一、参数配置化 1.1 问题分析 1.2 问题解决&#xff08;application.properties&#xff09; 1.2.1 application.properties 1.2.2 AliOSSUtils 1.2.3 启动服务-测试 二、yml配置文件 2.1 配置格式 2.1.1 新增 application.yml 2.1.2 启动服务 2.2 XML与prope…

linux 同时kill杀死多进程实践

使用场景 当程序中有使用到多进程且进程数较多的情况&#xff0c;如下图&#xff0c;且需要通过控制台杀死所有的 GSM_run.py 的进程时&#xff0c;利用 kill 命令一个一个的去结束进程是及其耗时且繁琐的&#xff0c;这时就需要我们的kill多进程的命令工作了。 批量 Kill 进程…

【ARM】Day9 cortex-A7核I2C实验(采集温湿度)

1. 2、编写IIC协议&#xff0c;采集温湿度值 iic.h #ifndef __IIC_H__ #define __IIC_H__ #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "led.h" /* 通过程序模拟实现I2C总线的时序和协议* GPIOF ---> AHB4* I2C1_S…

WiFi天线和NB-IoT天线不通用

表面看起来完全一样。但是把WiFi天线插到NB-IoT设备后&#xff0c;信号弱了很多。还导致设备反复重启

轮转数组——C语言

题目&#xff1a; 解法1&#xff1a;把最后一位数字移动到数组的第一位&#xff0c;然后将第二位开始的每一位往前移动一位 这种方法的时间复杂度O&#xff08;N^2&#xff09; 空间复杂度O&#xff08;1&#xff09; rotate(int* arr, int n, int k) {k % n;int i 0;for (i …

Prompt本质解密及Evaluation实战(一)

一、基于evaluation的prompt使用解析 基于大模型的应用评估与传统应用程序的评估不太一样&#xff0c;特别是基于GPT系列或者生成式语言模型&#xff0c;因为模型生成的内容与传统意义上所说的内容或者标签不太一样。 以下是借用了ChatGPT官方的evaluation指南提出的对结果的具…

Star History 月度开源精选|Llama 2 及周边生态特辑

7 月 18 日&#xff0c;Meta 发布了 Llama&#xff0c;大语言模型 Llama 1 的进阶版&#xff0c;可以自由免费用于研究和商业&#xff0c;支持私有化部署。 所以本期 Star History 的主题是&#xff1a;帮助你快速把 Llama 2 在自己机器上跑起来的开源工具&#xff0c;无论你的…

多环境开发

多环境 1、多环境开发&#xff08;YAML版&#xff09; 小结&#xff1a; 多环境开发需要设置若干种常用环境&#xff0c;例如开发、生产、测试环境yaml格式中设置多环境使用—区分环境设置边界每种环境的区别在于加载的配置属性不同启用某种环境时需要指定启动时使用该环境 …

高手进阶之路---pyqt自定义信号

高手进阶之路—pyqt自定义信号 1.思考问题为什么要自定义信号&#xff0c;qt5本身已有信号槽函数 # pushButton 被clicked的时候connect 函数print self.pushButton.clicked.connect(self.print)def print(self):print("我被点击了")或者使用 # 需要引入 pyqtSlo…

使用ffmpeg将WebM文件转换为MP4文件的简单应用程序

tiktok网上下载的short视频是webm格式的&#xff0c;有些程序无法处理该程序&#xff0c;比如roop程序&#xff0c;本文介绍了如何使用wxPython库创建一个简单的GUI应用程序&#xff0c;用于将WebM文件转换为MP4文件。这个应用程序使用Python编写&#xff0c;通过调用FFmpeg命令…

docker: /lib64/libc.so.6: version `GLIBC_2.32‘ not found (required by docker)

Linux环境 Ubuntu 22.04 docker 最新版 jenkins docker 版本(以下版本都会报错 jenkins/jenkins:centos7 jenkins/jenkins:lts-centos7 jenkins/jenkins:ltsdocker-compose.yml配置 version: 3.6 services:gitlab:image: twang2218/gitlab-ce-zhrestart: alwayscontainer_nam…

C#实现简单TCP服务器和客户端网络编程

在C#中进行网络编程涉及许多类和命名空间&#xff0c;用于创建和管理网络连接、传输数据等。下面是一些主要涉及的类和命名空间&#xff1a; System.Net 命名空间&#xff1a;这个命名空间提供了大部分网络编程所需的类&#xff0c;包括&#xff1a; IPAddress&#xff1a;用于…

第七章:借阅管理【基于Servlet+JSP的图书管理系统】

借阅管理 1. 借书卡 1.1 查询借书卡 借书卡在正常的CRUD操作的基础上&#xff0c;我们还需要注意一些特殊的情况。查询信息的时候。如果是管理员则可以查询所有的信息&#xff0c;如果是普通用户则只能查看自己的信息。这块的控制在登录的用户信息 然后就是在Dao中处理的时候需…

Linux 挂载局域网内共享目录

Linux 挂载局域网内共享目录 1、安装samba服务端2、samba服务端配置3、添加samba服务访问账户4、防火墙5、重启服务6、windows访问7、linux访问 1、安装samba服务端 sudo apt-get install -y samba yum install -y samba2、samba服务端配置 vim /etc/samba/smb.conf在文档尾部…

按钮权限控制

搜索关键字&#xff1a; 自定义指令传参| "自定义指令""dataset"|自定义指令dataset| "Vue""directives"|vue按钮权限实现 1、完整代码&#xff1a; <template> <div> <el-breadcrumb separator-class"el-icon…