Java基础整合

Java基础

开发

初级开发技能
     jsp +servlet + jdbc    15年前
     项目分层:
         控制层,表现层,action层,Controller层(servlet)
	 服务层,业务层,service层(没有对应框架,程序员主要写代码的地方)
	 持久层,数据访问层,DAO(data  access  object)层(jdbc)
中级开发技能
     servlet->struts1  struts2  springmvc 
     jdbc -> mybatis  hibernate ...

        spring (核心ioc 控制反转 DI依赖注入) 框架粘合剂,不取代任何框架,只整合框架
      
      SSM  (spring springmvc mybatis)
      SSH  (spring struts2  hibernate)
      SSH  (spring springmvc hibernate)
      SM  (springboot(简化spring搭建和使用过程框架)  mybatis)
     项目分层:
         控制层,表现层,action层,Controller层(struts1  struts2  springmvc)
	 服务层,业务层,service层(没有对应框架,程序员主要写代码的地方)
	 持久层,数据访问层,DAO(data  access  object)层(mybatis  hibernate)  @Repository   
	    不属于三层之内的  @Compenent

     前端 :  VUE   elementui   axios,jquery(ajax)  ...
高级开发技能
     目的高并发,高可靠。。。。
       
       微服务(springcloud  dubbo  tars等) 把项目拆开为多个模块  分布式和集群。。。
        
       分布式缓存技术(nosql): redis cluster  理论上缓存数据无限多。。。
       分布式搜索引擎(lucene,solr,elasticstack(elasticsearch logstash,kibana)等等)
       数据库集群技术(mycat+mysql(4台) 主从,读写分离,自动故障容错,分表分库)
       分布式文件服务器(hadoop(hdfs)  淘宝  tfs  谷歌  gfs...)  nginx+ftp  企业级文件服务器应用

       消息中间件框架(MQ=message queue)  微服务各服务之间的异步交互,可以解决服务器性能差别问题。。。。kafka   rabbitMQ  activeMQ...


     前端 :easyui  layui  nodejs  VUE   elementui  vantjs   axios,jquery(ajax)...

基础知识

String类型:null+“”=nullshort s = 1;
s=s+1; //编译不通过 (s+1)是int类型
s+=1; //编译通过 -> s=(short)(s+1);

iter  //遍历args数组
    
//自动类型转换:小容量转大容量
byte short char -> int -> long -> float -> double
byte short char 之间运算转换为int
    
    
//基本数据类型作为参数,传递给方法,方法运行结束后,原值不会发生改变
//引用数据类型作为参数,传递给方法,方法运行结束后,原值发生改变

构造方法
	//显式写出构造方法时,必须要带上无参构造方法
    //有父子类关系时,默认优先调用父类构造方法
    
static
	//静态的成员变量属于类,非静态的属于对象
    //静态的方法只能访问静态的成员变量
    //静态代码块,在实例化(构造方法)之前运行
    
final
	//final修饰成员变量要么直接初始化,要么在构造方法中初始化,初始化后不能修改成员变量的值
    //final修饰的方法不能被重写
    //final修饰的类不能被继承
    

Java内存模型
    栈(stack)
    	int a=1;
		Person person
    堆(heap)
    	new Person 
    方法区(non-heap)
    	类中定义的方法
        常量池(staticfinalString)
        静态域(静态成员变量)
    Integer-128-127,放在常量池中,超过范围则放在堆中)
            
lambta表达式
		https://blog.csdn.net/learningcoding/article/details/72539918
            
LocalDateTime类	(jdk新特性)
    //获取当前系统时间
    LocalDateTime.now() 
    //获取该年第几天
    LocalDateTime.getDayOfYear()	
    //获取该时间到某个时间的时间差start在外面,end在内部(不能用于数组比较器)
    time.until(LocalDateTime.now(), ChronoUnit.SECONDS)	
    //获取该天的多少秒
    time.getLong(ChronoField.SECOND_OF_DAY)
    //获取从1970-1-1到今天是多少天
    time.getLong(ChronoField.EPOCH_DAY)	
    //该时间是否在另一个时间之后,返回boolean,(isBefore 在之前,isEqual 相等)
    time.isAfter(time1)
    //时间格式化传递
   	LocalDateTime.parse(time,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    //获取开始结束时间差(毫秒)
    Duration.between(start,end).toMillis()
                 
继承
	父子类之间存在方法重写,子类优先
    父子类之间的构造方法,父类优先
                 
抽象类
    抽象类不能实例化
    给抽象类的属性赋值
    	1.继承这个抽象类,然后在子类中构造方法赋值 super(属性值...)
        2.通过子类的对象调用抽象类的set方法赋值
    获取抽象类的属性值
        通过子类的对象调用get方法获取值
                 
日志
   	//日志的级别
    //由低到高 trace<debug<info<warn<error<fatal
    //可以调整输出的日志级别,日志就只会在这个级别以后的高级别生效
    logger.trace("这是trace日志...");
    logger.debug("这是debug日志...");
    //SpringBoot默认是给我们使用的是info级别的
    logger.info("这是info日志...");
    logger.warn("这是warn日志...");
    logger.error("这是error日志...");
    logger.fatal("这是fatal日志...")
              
集合
   	list既可以按照下标删除,也可以按照对象删除,int要转换为Integer
    list通过Person的id删除元素
    list集合循环删除元素
        1.通过Iterator迭代器遍历删除,iterator.remove()
        2.用一个list记录要删除的数据,最后removeAll(list)
                 
泛型
    接口用泛型,MyInterface<Z>,实现该接口时要给Z指定泛型类型,如implements MyInterface<Person>
    实体类用泛型,Person<Z>还没有想好的属性,构造方法,set/get方法都可以使用,Person<Dog>
    方法使用泛型,public <Z> 返回类型 test(Z z){}; 需在方法上标记
    通配符
    	通配符上限,List<? extends xxx> 所有?匹配xxx的子类或者xxx  xxx也可为Z
        通配符下限,List<? super xxx> 所有?匹配xxx的父类或者xxx
    泛型方法<Z>和通配符的选择<?>
    	如果参数之间的类型有依赖关系,或者返回值是与参数之间有依赖关系的。那么就使用泛型方法
    	如果没有依赖关系的,就使用通配符,通配符会灵活—些.
	泛型的擦除
        把一个具有泛型信息的对象赋值给一个没有泛型信息的变量时,泛型信息会丢失
              
Map
	HashMap=数组+链表+红黑树(+hash表),链表长度大于8时,将链表转换为红黑树
    Map的遍历:
    	1.通过map.entrySet.for遍历
        2.通过迭代器遍历,map.entrySet.iterator获取迭代器 entry.getKey/getValue
        3.map.keySet遍历获取key,map.values遍历获取value
  
ResultSet
	返回结果集,表示数据库结果集的数据表
    ResultSetMetaData 元数据(记录表结构信息,数据库信息)
              
debug(断点调试)
	F9	进入下一个断点
    F8	逐行运行
    F7	进入到当前行的方法中
    Shift+F8	跳出当前方法
    Alt+F9	跳转到光标所在行
                
StopWatch
    sw.start(),sw.stop()
    计算代码执行时间
                 
线程创建
    继承Thread类
    实现Runnable接口
    	new Thread().start()
    实现Callable接口
        //创建一个多线程对象
		ImplementsCallable  implementsCallable= new ImplementsCallable(ip);
		//futureTask  对象获取返回值
		FutureTask<String>  task= new FutureTask<>(implementsCallable);
		//启动多线程
		new  Thread(task).start();
                 
多线程加锁的几种方式
    1.同步代码块
    	synchronized(this){...}
    2.同步方法
        public synchronized ...(){...}
    3.锁对象
        ReentrantLock lock = new ReentrantLock();
      	lock.lock();
        try {...} finally {lock.unlock();}
                 
sleep和wait方法的区别
    sleep方法没有释放锁,而wait方法释放了锁
   
反射
Class
	getName()获得类的完整路径名字
    newInstance()创建类的实例
    getPackage()获得类的包
    getSimpleName()获得类的名字
    getSuperclass()获得当前类继承的父类的名字
    getInterfaces()获得当前类实现的类或是接口
                 
Field
    //通过Class对象获取,其属性要为public的
    //设置私有属性访问权限id.setAccessible(true);
    getField(String name)获得某个公有的属性对象
    getFields()获得所有公有的属性对象
    getDeclaredField(String name)获得某个属性对象
   	getDeclaredFields()获得所有属性对象
   		equals(Object obj)属性与obj相等则返回true
        get(Object obj)获得obj中对应的属性值
        set(Object obj, Object value)设置obj中对应属性值
                 
InetAddress
    getLocalHost()	返回本地主机
    getByName(String host)	根据主机名获取主机
    isReachable()	是否可达
                 
代理
	静态代理
    	基于接口的静态代理
        基于继承的静态代理
    动态代理
    	基于接口的动态代理
        不基于接口的cglib动态代理
                 
定时任务
    springmvc.xml
    	xmlns:task="http://www.springframework.org/schema/task" 
		http://www.springframework.org/schema/task  
		http://www.springframework.org/schema/task/spring-task-3.2.xsd 
		<task:annotation-driven />
		<context:component-scan base-package="com.xxx.xxx" />
                 
    @Scheduled(cron="0/1 * * * * *")	//每一秒执行一次,秒,分钟,小时..
   	public void test(){
        System.out.println("new Date()");
    }

迭代器

//迭代器遍历
Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}

重写equals方法

@Override
public boolean equals(Object o) {
    //判断内存地址是否相同
    if (this == o) {
        return true;
    }
    //判断对象是否为空,并且两个对象是否是同一类
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    //判断对象的id是否相同
    Person person = (Person) o;
    return id == person.id;
}

九九乘法表

package hello;

/**
 * @author :IvanZ
 * @date :Created in 2020/11/19 18:08
 * @description:九九乘法表
 * @modified By:
 * @version: 1.0
 */
public class NineNine {
    public static void main(String[] args) {
        for (int i = 1; i < 10 ; i++) {
            for (int j = 1; j < i+1 ; j++) {
                System.out.print(j+"*"+i+"="+i*j+" ");
            }
            System.out.println("");
        }
    }
}

等边三角形

package hello;

/**
 * @author :IvanZ
 * @date :Created in 2020/11/19 18:17
 * @description:等边三角形
 * @modified By:
 * @version: 1.0
 */
public class Trangle {
    public static void main(String[] args) {
        for (int i = 0; i <10; i++) {
            for (int j = 0; j <i ; j++) {
                print(i,j);
            }
            System.out.println("");
        }

        for (int i = 10; i >0 ; i--) {
            for (int j = 0; j <i ; j++) {
                print(i,j);
            }
            System.out.println("");
        }
    }

    public static void print(int i,int j){
        if (i%2==0&&j%2==1){
            System.out.print(" ");
        }else if (i%2==1&&j%2==0){
            System.out.print(" ");
        }else {
            System.out.print("*");
        }
        System.out.print("     ");
    }
}

逢七过

/**
 * @author :IvanZ
 * @version :
 * @date :Created in 2020/11/20 14:40
 * @description :逢七过
 * @modified By:
 */
public class SevenPass {
    public static void main(String[] args) {
        int count = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 7 == 0 || i % 10 == 7 || i / 10 == 7){
                System.out.println("过");
                count++;
                continue;
            }
            System.out.println(i);
        }
        System.out.println("一共"+count+"个过");
    }
}

100以内的质数

/**
 * @author :IvanZ
 * @version : 1.0
 * @date :Created in 2020/11/20 17:07
 * @description :100以内的质数
 * @modified By:
 */
public class PrimeNumbers {
    public static void main(String[] args) {
        int total = 0;
        for (int i = 2; i < 100; i++) {
            int count = 0;
            for (int j = 1; j <= i/2; j++) {
                if (i % j == 0){
                    count++;
                }
            }
            if (count == 1){
                System.out.println(i);
                total++;
            }
        }
        System.out.println("100以内的质数一共有"+total+"个");
    }
}

JS实现计算器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算器</title>
    <script>
        window.onload=function () {
            //获取元素
            var divide = document.getElementById("/");
            var seven = document.getElementById("7");
            var eight = document.getElementById("8");
            var nine = document.getElementById("9");
            var mul = document.getElementById("*");
            var four = document.getElementById("4");
            var five = document.getElementById("5");
            var six = document.getElementById("6");
            var minus = document.getElementById("-");
            var one = document.getElementById("1");
            var two = document.getElementById("2");
            var three = document.getElementById("3");
            var sum = document.getElementById("+");
            var clear = document.getElementById("C");
            var zero = document.getElementById("0");
            var point = document.getElementById(".");
            var equal = document.getElementById("=");
            var show = document.getElementById("show");

            //显示器显示计算字符串
            function showStr(str) {
                show.innerHTML=str;
            }

            //计算字符串
            var str = "";

            //数字
            zero.onclick=function(){
                str += "0";
                showStr(str);
            }
            one.onclick=function () {
                str += "1";
                showStr(str);
            }
            two.onclick = function () {
                str += "2";
                showStr(str);
            }
            three.onclick = function () {
                str += "3";
                showStr(str);
            }
            four.onclick = function () {
                str += "4";
                showStr(str);
            }
            five.onclick = function () {
                str += "5";
                showStr(str);
            }
            six.onclick = function () {
                str += "6";
                showStr(str);
            }
            seven.onclick = function () {
                str += "7";
                showStr(str);
            }
            eight.onclick = function () {
                str += "8";
                showStr(str);
            }
            nine.onclick = function () {
                str += "9";
                showStr(str);
            }

            //小数点
            point.onclick = function(){
                str += ".";
                showStr(str);
            }

            //加减乘除
            sum.onclick=function () {
                str += "+";
                showStr(str);
            }
            minus.onclick=function(){
                str += "-";
                showStr(str);
            }
            mul.onclick=function(){
                str += "*";
                showStr(str);
            }
            divide.onclick=function(){
                str += "/";
                showStr(str);
            }

            //等号
            equal.onclick=function(){
                str += "="+eval(str);
                showStr(str)
                str = "";
            }
            //清除
            clear.onclick=function(){
                str = "";
                showStr(str);
            }



        }
    </script>
    <style>
        td{
            text-align: center;
            width: 100px;
            height: 100px;
        }

        #show{
            font-size: 30px;
            font-weight: bold;
            color: red;
        }

        #calc{
            font-size: 30px;
            font-weight: bold;
            background-color: gray;
            color: white;
        }
        input{
            width: 100px;
            height: 100px;
        }
    </style>
</head>
<body>
    <table border="1px">
        <tr>
            <td colspan="4" id="calc">计算器</td>
        </tr>
        <tr>
            <td colspan="3" id="show">显示屏</td>
            <td id="/"><input type="button" value="/"></td>
        </tr>
        <tr>
            <td id="7"><input type="button" value="7"></td>
            <td id="8"><input type="button" value="8"></td>
            <td id="9"><input type="button" value="9"></td>
            <td id="*"><input type="button" value="*"></td>
        </tr>
        <tr>
            <td id="4"><input type="button" value="4"></td>
            <td id="5"><input type="button" value="5"></td>
            <td id="6"><input type="button" value="6"></td>
            <td id="-"><input type="button" value="-"></td>
        </tr>
        <tr>
            <td id="1"><input type="button" value="1"></td>
            <td id="2"><input type="button" value="2"></td>
            <td id="3"><input type="button" value="3"></td>
            <td id="+"><input type="button" value="+"></td>
        </tr>
        <tr>
            <td id="C"><input type="button" value="C"></td>
            <td id="0"><input type="button" value="0"></td>
            <td id="."><input type="button" value="."></td>
            <td id="="><input type="button" value="="></td>
        </tr>
    </table>
</body>
</html>

计算每天工作时长

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;

/**
 * @author :IvanZ
 * @version : 1.0
 * @date :Created in 2020/11/23 16:14
 * @description :计算每天工作时长,输入错误重新输入
 * @modified By:
 */
public class WorkTime2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        long startTime;
        long endTime;

        while (true) {
            try {
                System.out.println("请输入开始工作的时间:");
                String start = sc.nextLine();
                //转换为毫秒数
                startTime = sdf.parse(start).getTime();
                break;
            } catch (ParseException e) {
                System.out.println("输入错误,请重新输入:");
            }
        }

        while (true) {
            try {
                System.out.println("请输入结束工作的时间:");
                String end = sc.nextLine();
                //转换为毫秒数
                endTime = sdf.parse(end).getTime();
                break;
            } catch (ParseException e) {
                System.out.println("输入错误,请重新输入:");
            }
        }

        //计算出工作时间的毫秒数
        long time = endTime - startTime;

        System.out.println("一共工作了" + time / (1000 * 60 * 60) + "小时" + (time / 1000 / 60) % 60 + "分钟" + (time / 1000) % 60 + "秒");

    }
}

由上下班时间求员工工作时间

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * @author :IvanZ
 * @version : 1.0
 * @date :Created in 2020/11/23 17:00
 * @description :由员工上下班时间求员工工作时间,不满8小时提示早退
 * @modified By:
 */
public class Employee {
    int id;
    String name;
    LocalDateTime checkOnTime;
    LocalDateTime checkOutTime;

    public Employee() {
    }

    public Employee(int id, String name, LocalDateTime checkOnTime, LocalDateTime checkOutTime) {
        this.id = id;
        this.name = name;
        this.checkOnTime = checkOnTime;
        this.checkOutTime = checkOutTime;
    }

    /**
     * @param employee: 传递员工对象
     * @return void
     * @create by: IvanZ
     * @description : 自我介绍
     * @create time: 2020/11/23 18:01
     */
    public void introduce(Employee employee) {
        System.out.println("我是" + employee.name + ",我的员工编号是" + id);
    }

    /**
     * @param employee: 传递员工对象
     * @return java.lang.String
     * @create by: IvanZ
     * @description : 获取员工工作的时间,若工作时间不到8小时提示早退
     * @create time: 2020/11/23 18:01
     */
    public String getWorkTime(Employee employee) {
        //获取上下班秒数的时间差
        long workSeconds = ChronoUnit.SECONDS.between(employee.checkOnTime, employee.checkOutTime);
        //工作的小时数
        long hour = workSeconds / (60 * 60);
        //工作的分钟数
        long minute = workSeconds / 60 % 60;
        //工作的秒数
        long second = workSeconds % 60;
        //距工作8小时还需多少秒
        long restSeconds = 8 * 60 * 60 - workSeconds;
        //如果工作时间不到8小时
        if (hour < 8) {
            System.out.println("早退!还需工作" + restSeconds / (60 * 60) + "小时" + restSeconds / 60 % 60 + "分钟" + restSeconds % 60 + "秒" + "可以下班");
            return "";
        } else {
            return hour + "小时" + minute + "分钟" + second + "秒";
        }
    }

    public static void main(String[] args) {
        //设置上班时间
        LocalDateTime checkOnTime = LocalDateTime.parse("2020-11-23T08:20:00");
        //设置下班时间
        LocalDateTime checkOutTime = LocalDateTime.parse("2020-11-23T20:30:00");
        //实例化员工对象并传值
        Employee employee = new Employee(1, "IvanZ", checkOnTime, checkOutTime);
        //调用introduce和getWorkTime方法
        employee.introduce(employee);
        System.out.println(employee.getWorkTime(employee));
    }
}

JQuery实现计算器(简单)

相比于JS,在JQuery中:

.innerHTML=str  -->  .html(str);

在某个元素的事件方法中若调用该元素
this -->  $(this)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算器</title>
    <script src="jquery-3.4.1.js"></script>
    <script>
        $(function () {
            //设置初始字符串
            let str = "";
            //获取input按钮
            let $input = $("input");
            //点击input按钮事件
            $input.click(function () {
                //获取该按钮元素
                let $this = $(this);
                //在显示器上展示
                showStr(str);
                switch ($this.val()) {
                    //如果该按钮的值等于 “=”
                    case "=":
                        //进行计算
                        str += "="+eval(str);
                        showStr(str)
                        str = "";
                        break;
                    //如果该按钮的值等于“C”
                    case "C":
                        //清空
                        str = "";
                        showStr(str);
                        break;
                    default:
                        str += $this.val();
                        showStr(str);
                }
            });

            //显示器显示计算字符串
            function showStr(str) {
                $("#show").html(str);
            }
        });
    </script>
    <style>
        td{
            text-align: center;
            width: 100px;
            height: 100px;
        }

        #show{
            font-size: 30px;
            font-weight: bold;
            color: red;
        }

        #calc{
            font-size: 30px;
            font-weight: bold;
            background-color: gray;
            color: white;
        }
        input{
            width: 100px;
            height: 100px;
        }
    </style>
</head>
<body>
<table border="1px">
    <tr>
        <td colspan="4" id="calc">计算器</td>
    </tr>
    <tr>
        <td colspan="3" id="show">显示屏</td>
        <td><input type="button" value="/"></td>
    </tr>
    <tr>
        <td><input type="button" value="7"></td>
        <td><input type="button" value="8"></td>
        <td><input type="button" value="9"></td>
        <td><input type="button" value="*"></td>
    </tr>
    <tr>
        <td><input type="button" value="4"></td>
        <td><input type="button" value="5"></td>
        <td><input type="button" value="6"></td>
        <td><input type="button" value="-"></td>
    </tr>
    <tr>
        <td><input type="button" value="1"></td>
        <td><input type="button" value="2"></td>
        <td><input type="button" value="3"></td>
        <td><input type="button" value="+"></td>
    </tr>
    <tr>
        <td><input id="clear" type="button" value="C"></td>
        <td><input type="button" value="0"></td>
        <td><input type="button" value="."></td>
        <td><input id="equal" type="button" value="="></td>
    </tr>
</table>
</body>
</html>

冒泡排序

//冒泡排序
for (int i = 1; i <arr.length ; i++) {
    for (int j = 0; j <arr.length-i ; j++) {
        if (arr[j] > arr[j+1]){
            int temp = arr[j+1];
            arr[j+1] = arr[j];
            arr[j] = temp;
        }
    }
}

计算n个数之和(可变参数)

/**
 * @create by: IvanZ
 * @description : 计算n个数之和
 * @create time: 2020/11/24 11:08
 * @param ints:
 * @return int
 */
public static int add1(int[] ints){
    int sum = 0;
    for (int i = 0; i < ints.length; i++) {
        sum += ints[i];
    }
    return sum;
}

//使用可变参数,可变参数必须放在参数列表最后面
public static int add2(int ...ints){
    int sum = 0;
    for (int i = 0; i < ints.length; i++) {
        sum += ints[i];
    }
    return sum;
}

比较器(用于根据对象的某个属性排序)

/**
 * @create by: IvanZ
 * @description : 比较器,需实现Comparable接口,并重写compareTo方法,负数< 0= 正数>
 * @create time: 2020/11/24 11:50
 * @param o:
 * @return int
 */
@Override
public int compareTo(Student o) {
    if (this.xxx.isBefore(o.xxx)) {
        return -1;
    }
    if (this.xxx.isAfter(o.xxx)){
        return 1;
    }
    return 0;
}

传递随机LocalDateTime参数

Random random = new Random();
//随机传入LocalDateTime参数
for (int i = 0; i < students.length; i++) {
    int s = random.nextInt(60);
    String str;
    if (s < 10){
        str = "0" + s;
    }else {
        str = "" + s;
    }
    students[i] = new Student("Ivan"+i,18,LocalDateTime.parse("2020-11-24T08:"+str+":13"));
}

输入一个字符串,统计每个字符个数

package work;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * @author :IvanZ
 * @version : 1.0
 * @date :Created in 2020/11/27 14:33
 * @description :输入一个字符串,统计字符个数
 * @modified By:
 */
public class Work1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入字符串:");
        String string = sc.nextLine();
        String[] strings = string.split("");

        Map<String,Integer> map = new HashMap<>(100);

        for (String s : strings) {
            if (map.get(s) == null) {
                map.put(s, 1);
            } else {
                map.put(s, map.get(s) + 1);
            }
        }
        System.out.println(map);
    }
}

求数组中两数之和为目标值的两数下标

package work;

import java.util.Arrays;

/**
 * @author :IvanZ
 * @version : 1.0
 * @date :Created in 2020/11/27 21:53
 * @description :给定一个整数数组和一个目标值Target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标.
 * 你可以假设每种输入只会对应一个答案.但是,数组中同一个元素不能使用两遍.
 * @modified By:
 */
public class Work2 {
    public static void main(String[] args) {
        //定义数组
        int[] nums = {4,5,7,3,2,6};
        //定义target
        int target = 10;
        //结果数组
        int[] result = new int[2];
        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = i+1; j < nums.length ; j++) {
                if (nums[i] + nums[j] == target){
                    result[0] = i;
                    result[1] = j;
                    System.out.println(Arrays.toString(result));
                    break;
                }
            }
        }
    }
}

图书管理系统

public class BookDaoImplTest {
    BookDao bookDao = new BookDaoImpl();

    @Test
    public void bookManage(){
        while (true){
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入1:查询所有,2:删除图书,3:查询少于库存上限的图书本数,4:查询出版社的图书,5:添加图书,q:退出");
            String s = sc.nextLine();
            switch (s){
                //查询所有
                case "1":
                    //获取查询到的所有图书
                    List<Map<String, Object>> all = bookDao.findAll();
                    //遍历输出
                    for (Map<String, Object> stringObjectMap : all) {
                        System.out.println(stringObjectMap);
                    }
                    System.out.println();
                    break;
                //删除图书
                case "2":
                    System.out.println("请输入你要删除的图书ISBN:");
                    int isbn = sc.nextInt();
                    bookDao.deleteByIsbn(isbn);
                    System.out.println();
                    break;
                //查询少于库存上限的图书本数
                case "3":
                    System.out.println("请输入你要查询的库存上限:");
                    int currcount = sc.nextInt();
                    int lessCurrcount = bookDao.findLessCurrcount(currcount);
                    System.out.println("库存在"+currcount+"以下的图书有:"+lessCurrcount+"本");
                    System.out.println();
                    break;
                //查询出版社的图书
                case "4":
                    System.out.println("请输入你要查询的出版社:");
                    String publish1 = sc.nextLine();
                    //接收查询到的信息
                    List<Map<String, Object>> bookByPublish1 = bookDao.findBookByPublish(publish1);
                    System.out.println(publish1+"的图书有:");
                    //遍历输出
                    for (Map<String, Object> byPublish : bookByPublish1) {
                        System.out.println(byPublish);
                    }
                    System.out.println();
                    break;
                //添加图书
                case "5":
                    System.out.println("请按照name、author、publish、price、currcount输入图书信息,以中文“,”分割:");
                    //定义key值
                    String[] keys = {"name","author","publish","price","currcount"};
                    //接收value值
                    String[] values = sc.next().split(",");
                    Map<String,Object> map = new HashMap<>();
                    for (int i = 0; i < values.length; i++) {
                        //放入map
                        map.put(keys[i],values[i]);
                    }
                    int i = bookDao.insertBook(map);
                    System.out.println("添加的图书的isbn码为:"+i);
                    System.out.println();
                    break;
                //退出
                case "q":
                    return;
                //重新输入
                default:
                    System.out.println("请重新输入:");
                    System.out.println();
                    break;
            }
        }
    }
}    

登录过滤器

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        //获取session
        HttpSession session = request.getSession();
        //获取页面uri地址
        String uri = request.getRequestURI();
        //判断是否包含loginServlet
        if (uri.contains("/loginServlet")){
            //放行
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            if (session.getAttribute("username")!=null){
                //放行
                filterChain.doFilter(servletRequest,servletResponse);
            }else {
                //转发到login.jsp
               request.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse); }
        }
    }

监听在线人数

/**
 * @author :IvanZ
 * @version : 1.0
 * @date :Created in 2020/12/7 18:41
 * @description :当前在线人数
 * @modified By:
 */
@WebListener
public class CountListener implements HttpSessionAttributeListener {
    static String username = "username";
    public static int count = 0;

    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        //获取添加的session名称
        String name = httpSessionBindingEvent.getName();
        //如果添加的session名是username
        if (username.equals(name)) {
            count++;
        }
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        //获取删除的session名称
        String name = httpSessionBindingEvent.getName();
        //如果删除的session名是username
        if (username.equals(name)) {
            count--;
        }

    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
    }
}

js实现显示时间

 function run(){
 var time = new Date();//获取系统当前时间
 var year = time.getFullYear();
 var month = time.getMonth()+1;
 var date= time.getDate();//系统时间月份中的日
 var day = time.getDay();//系统时间中的星期值
 var weeks = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
 var week = weeks[day];//显示为星期几
 var hour = time.getHours();
 var minutes = time.getMinutes();
 var seconds = time.getSeconds();
 console.log(seconds);
 if(month<10){
 month = "0"+month; 
 }
 if(date<10){
 date = "0"+date; 
 }
 if(hour<10){
 hour = "0"+hour; 
 }
 if(minutes<10){
 minutes = "0"+minutes; 
 }
 if(seconds<10){
 seconds = "0"+seconds; 
 }
 //var newDate = year+"年"+month+"月"+date+"日"+week+hour+":"+minutes+":"+seconds;
 document.getElementById("show").innerHTML = year+"年"+month+"月"+date+"日"+week+hour+":"+minutes+":"+seconds;
 setTimeout('run()',1000);
 }
  
 run();

SpringBoot实现多线程的邮件发送

MailServiceImpl

package com.cloudwise.ivan.service.serviceImpl;

import com.cloudwise.ivan.service.MailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

/**
 * @create by: IvanZ
 * @description : 实现发送邮件
 * @create time: 2021/1/6 19:10
 */
@Service
public class MailServiceImpl implements MailService {

    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.from}")
    private String from;

    @Async("myTaskAsyncPool")
    @Override
    public void sendSimpleMail(String to, String subject, String content) {
        //创建SimpleMailMessage对象
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件发送人
        message.setFrom(from);
        //邮件接收人
        message.setTo(to);
        //邮件主题
        message.setSubject(subject);
        //邮件内容
        message.setText(content);
        //发送邮件
        mailSender.send(message);
    }

    @Override
    public void sendHtmlMail(String to, String subject, String content) {
        //获取MimeMessage对象
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper;
        try {
            messageHelper = new MimeMessageHelper(message, true);
            //邮件发送人
            messageHelper.setFrom(from);
            //邮件接收人
            messageHelper.setTo(subject);
            //邮件主题
            message.setSubject(subject);
            //邮件内容,html格式
            messageHelper.setText(content, true);
            //发送
            mailSender.send(message);
            //打印邮件发送情况
            System.out.println("邮件已经发送");
        } catch (MessagingException e) {
            System.out.println("发送邮件时发生异常");
        }
    }

    @Override
    public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            helper.addAttachment(fileName, file);
            mailSender.send(message);
            //打印邮件发送情况
            System.out.println("邮件已经发送");
        } catch (MessagingException e) {
            System.out.println("发送邮件时发生异常");
        }
    }
}

Socket通信服务端

//服务器程序创建一个ServerSocket
ServerSocket serverSocket = new ServerSocket(7000);
//然后再用accept方法等待客户来连接
Socket socket = serverSocket.accept();
//服务器通过scoket. getInputStream获取输入流读取客户端发送的消息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//读取一行数据
String clientLine = bufferedReader.readLine();
//打印客户端发送的消息
System.out.println("client:"+clientLine);
//回复客户端信息
OutputStream outputStream = socket.getOutputStream();
//autoFlush:true自动刷新缓冲区
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream),true);
//获取控制台输入的信息,往客户端打印
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
//将字节流转为字符流
BufferedReader replyBufferReader = new BufferedReader(inputStreamReader);
String serverLine = replyBufferReader.readLine();
while (!"bye".equals(clientLine)){
    printWriter.println("server:"+serverLine);
    //继续接受客户端回传的信息
    clientLine = bufferedReader.readLine();
    //打印客户端发送的消息
    System.out.println("client:"+clientLine);
    //继续发送信息
    serverLine = replyBufferReader.readLine();
}

Socket通信客户端

//new一个socket
Socket socket = new Socket("127.0.0.1",7000);
//服务器通过scoket. getInputStream获取输入流读取客户端发送的消息
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//回复客户端信息
OutputStream outputStream = socket.getOutputStream();
//autoFlush:true自动刷新缓冲区
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream),true);
//获取控制台输入的信息,往客户端打印
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
//将字节流转为字符流
BufferedReader replyBufferReader = new BufferedReader(inputStreamReader);
String clientLine = replyBufferReader.readLine();
String serverLine = "";
while (!"bye".equals(serverLine)){
    printWriter.println(clientLine);
    //继续接受客户端回传的信息
    serverLine = bufferedReader.readLine();
    //打印客户端发送的消息
    System.out.println(serverLine);
    //继续发送信息
    clientLine = replyBufferReader.readLine();
}

多线程Socket通信服务端

package com.cloudwise.network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author IvanZ
 * @version 1.0
 * @date Created on 2021/1/19 14:49
 * @description 多线程服务端
 * @modifiedBy
 */
public class MultiThreadSocket implements Runnable{
    Socket socket;

    public MultiThreadSocket(Socket socket) {
        this.socket = socket;
    }

    public MultiThreadSocket() {
    }

    @Override
    public void run() {
        try {
            //服务器通过scoket. getInputStream获取输入流读取客户端发送的消息
            InputStream inputStream = socket.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            //读取一行数据
            String clientLine = bufferedReader.readLine();
            //打印客户端发送的消息
            System.out.println("client"+Thread.currentThread().getName()+":"+clientLine);
            //回复客户端信息
            OutputStream outputStream = socket.getOutputStream();
            //autoFlush:true自动刷新缓冲区
            PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream),true);
            //获取控制台输入的信息,往客户端打印
            InputStreamReader inputStreamReader = new InputStreamReader(System.in);
            //将字节流转为字符流
            BufferedReader replyBufferReader = new BufferedReader(inputStreamReader);
            String serverLine = replyBufferReader.readLine();
            while (!"bye".equals(clientLine)){
                printWriter.println("server:"+serverLine);
                //继续接受客户端回传的信息
                clientLine = bufferedReader.readLine();
                //打印客户端发送的消息
                System.out.println("client"+Thread.currentThread().getName()+":"+clientLine);
                //继续发送信息
                serverLine = replyBufferReader.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //服务器程序创建一个ServerSocket
        try {
            ServerSocket serverSocket = new ServerSocket(7000);
            while (true) {
                Socket socket = serverSocket.accept();
                MultiThreadSocket multiThreadSocket = new MultiThreadSocket(socket);
                new Thread(multiThreadSocket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Udp服务器

package com.cloudwise.network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author IvanZ
 * @version 1.0
 * @date Created on 2021/1/19 16:58
 * @description Udp服务器端
 * @modifiedBy
 */
public class UdpServer {
    public static void main(String[] args) throws Exception{
        byte[] bytes = new byte[1024];
        //接收方(服务器)创建一个DatagramSocket,指定端口号不然无法接收信息
        DatagramSocket datagramSocket = new DatagramSocket(6000);
        // 接收方创建一个DatagramPacket(缓存区不需要指定ip)
        DatagramPacket packet = new DatagramPacket(bytes, 1024);
        //调用DatagramSocket.receive方法进行接收
        datagramSocket.receive(packet);
        //打印接收的数据
        byte[] data = packet.getData();
        String message = new String(data, 0, data.length);
        System.out.println(message);
    }
}

Udp客户端

package com.cloudwise.network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @author IvanZ
 * @version 1.0
 * @date Created on 2021/1/19 16:58
 * @description Udp客户端
 * @modifiedBy
 */
public class UdpClient {
    public static void main(String[] args) throws Exception {
        // 发送方(客户端)创建一个DatagramSocket;
        DatagramSocket socket = new DatagramSocket();
        // 发送方创建一个DatagramPacket_指定IP 指定端口号
        // 链接服务器
        String message=" I love  you ";
        InetAddress host = InetAddress.getByName("localhost");
        DatagramPacket datagramPacket= new DatagramPacket(message.getBytes(),message.length(),host,6000);
        //发送方调用DatagramSocket的send方法发送信息
        socket.send(datagramPacket);
    }
}

伪装FeiQ发送信息

String Version="1_lbt4_0#128#000C29D68D8F#0#0#0#2.5a";
Long id=System.currentTimeMillis();
String user="范冰冰";
String host="PC-fhdskfhdsfh";
//指令类型 209 震动
long IPMSG_SENDMSG = 0x00000020;
//发送方创建一个DatagramSocket
DatagramSocket datagramSocket = new DatagramSocket();
//发送方创建一个DatagramPacket 指定IP 指定端口号
String message="I love you";
message=Version+":"+id+":"+user+":"+host+":"+IPMSG_SENDMSG+":"+message;
//获取主机
InetAddress localhost = InetAddress.getByName("localhost");
DatagramPacket datagramPacket = new DatagramPacket(message.getBytes("gbk"), message.length(), localhost, 2425);
//发送方调用send方法发送信息
datagramSocket.send(datagramPacket);

基于接口的动态代理

package com.cloudwise.tomorrow.proxy;

import com.cloudwise.tomorrow.log.MyLogUtil;

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

/**
 * @author IvanZ
 * @version 1.0
 * @date Created on 2021/1/21 11:54
 * @description 基于接口的动态代理
 * @modifiedBy
 */
public class ProxyDynamicInterface implements InvocationHandler {
    private Object obj;
    private MyLogUtil logUtil = new MyLogUtil();

    /**
     * 获取代理对象
     * @param target: 目标对象,接口的实现类的实例
     * @return java.lang.Object
     * @createBy IvanZ
     * @createTime 2021/1/21 12:01
     */
    public Object getProxyObj(Object target){
        obj = target;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }


    /**
     * 目标对象的方法被调用的时候,自动执行invoke方法中的内容
     * @param proxy: 代理对象
     * @param method: 方法
     * @param args: 方法的参数
     * @return java.lang.Object
     * @createBy IvanZ
     * @createTime 2021/1/21 12:01
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("目标对象方法开始执行");
        //方法执行之前增强处理
        Object o = method.invoke(obj, args);
        //方法执行之后增强处理
        logUtil.log(method.getName());
        return o;
    }
}



//执行
ProxyDynamicInterface proxyDynamicInterface = new ProxyDynamicInterface();
PhoneService proxyObj = (PhoneService) proxyDynamicInterface.getProxyObj(new PhoneServiceImpl());
proxyObj.salPhone(5);

不基于接口的cglib动态代理

package com.cloudwise.tomorrow.proxy;

import com.cloudwise.tomorrow.log.MyLogUtil;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author IvanZ
 * @version 1.0
 * @date Created on 2021/1/21 15:06
 * @description 不基于接口的cglib动态代理
 * @modifiedBy
 */
public class ProxyDynamicCGLib {
    MyLogUtil logUtil = new MyLogUtil();
    public  Object getProxyObj(Class<?> clazz){
        //定义一个字节码增强器
        Enhancer enhancer = new Enhancer();
        //设置增强对象,目标对象
        enhancer.setSuperclass(clazz);
        //给增强器设置回调函数
        // Interceptor是拦截器的意思,拦截目标对象的方法
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //执行目标对象的方法
                Object invokeSuper = methodProxy.invokeSuper(o, objects);
                //增强处理
                logUtil.log(method.getName());
                return invokeSuper;
            }
        });
        //返回代理对象
        return enhancer.create();
    }
}

根据request请求获取ip

/**
 * 获取ip
 * @param request:
 * @return java.lang.String
 * @createBy IvanZ
 * @createTime 2021/1/21 17:38
 */
public static String getRemoteAddr(HttpServletRequest request) {
    String ip = request.getHeader("X-real-ip");
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("x-forwarded-for");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("HTTP_CLIENT_IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
    if ("0:0:0:0:0:0:0:1".equals(ip)) {
        ip = "127.0.0.1";
    }
    if (ip.split(",").length > 1) {
        ip = ip.split(",")[0];
    }
    return ip;
}

日志切面配置类

package com.cloudwise.trademark.aop;

import com.cloudwise.trademark.entity.Log;
import com.cloudwise.trademark.entity.User;
import com.cloudwise.trademark.service.LogService;
import com.cloudwise.trademark.util.MyUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @author IvanZ
 * @version 1.0
 * @date Created on 2021/1/21 16:50
 * @description 日志切面类
 * @modifiedBy
 */
@EnableAspectJAutoProxy
@Aspect
@Component("logAspect")
public class LogAspect {
    @Autowired
    LogService logService;

    @Pointcut("execution(* com.cloudwise.trademark.controller.*.*(..))")
    private void pt(){
    }

    @Around("pt()")
    public Object saveLog(ProceedingJoinPoint pjp){
        Object rtValue = null;
        try {
            //得到方法所需的参数
            Object[] args = pjp.getArgs();

            //明确调用业务层方法(切入点方法)
            rtValue = pjp.proceed(args);

            return rtValue;
        } catch (Throwable throwable) {
            throw new RuntimeException(throwable);
        } finally {
            //类名
            String className = pjp.getTarget().getClass().getName();
            //方法名
            String methodName = pjp.getSignature().toString().split("\\.")[pjp.getSignature().toString().split("\\.").length-1];
            //参数
            String params = Arrays.toString(pjp.getArgs());
            //获取ip
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();
            String ip = MyUtil.getRemoteAddr(request);
            //获取session中的user
            Log log = new Log();
            if (request.getSession().getAttribute("user") != null){
                User user = (User)request.getSession().getAttribute("user");
                log.setLoginName(user.getLoginName());
                log.setUserName(user.getUserName());
            }

            log.setClassName(className);
            log.setMethodName(methodName);
            log.setParams(params);
            log.setIp(ip);
            //添加log
            logService.insert(log);
        }
    }
}

springboot启动时执行任务

平常开发中有可能需要实现在项目启动后执行的功能,SpringBoot提供的一种简单的实现方案就是添加一个model并实现CommandLineRunner接口,实现功能的代码放在实现的run方法中

@Component
public class MyStartupRunner implements CommandLineRunner {

  @Override
  public void run(String... args) throws Exception {
  	System.out.println(">>>>>>>>>>>>>>>服务启动执行,执行加载数据等操作<<<<<<<<<<<<<");
  }
}

流方式去除List中不符合要求的元素

List<AppLicenseStatusBean> statuses = heartDao.getAgentStatus();
List<AppLicenseStatusBean> non_status = statuses.parallelStream().filter(status -> {
    long last_heartbeat_time = status.getLastHeartbeatTime();
    long agent_id = status.getAgentId();
    String version = status.getVersion();
    long diff_time = current_time - last_heartbeat_time;
    long timeOutMs = settingsConfig.getLicenseTimeOut() == 0 ? 1000000L:settingsConfig.getLicenseTimeOut();
    boolean un_heart = diff_time > timeOutMs;
    if (un_heart) {
        log.info("agent_id: {},, version: {},diff time : {},last_heartbeat_time: {} ,timeout:{}", agent_id, version, diff_time, last_heartbeat_time,timeOutMs);
    }
    return un_heart;
}).collect(Collectors.toList());
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼ۖ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值