java怎么做3d可视化图形

结果如下:


 实现的功能:

1、从数据库里面查询数据,然后呈现在图形上面

2、可以放大和缩小

3、按住鼠标不断的调整图形的视角


jar包依赖

Matplot3d_4_dhj_f(v1.0).jar    https://gitee.com/tanling8334/Matplot3D-for-Java


代码如下

package tanling.matplot4j.demo;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TextFileHelper {
	/*
	 * author:@命运的信徒
	 * date:2019/2/19
	 * arm:获取路径
	 */
	public static String getText(String filePath){
		
		try {
			//加载这个类的资源加载器
			InputStream ips=TextFileHelper.class.getClassLoader().getResourceAsStream(filePath);
			//输入流读取
			BufferedReader reader=new BufferedReader(new InputStreamReader(ips));
			
			String buffer;
			
			StringBuffer sb=new StringBuffer();
			
			while(true){
				
				buffer=reader.readLine();
				
				if(buffer==null)
					break;
			
				sb.append(buffer);
				sb.append("\n");
			}

			return sb.toString();
			
		} catch (Exception e) {
			return null;
		}
		
	}
}
package tanling.matplot4j.demo;
import java.util.Enumeration;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;
import tanling.matplot_4j.comment.SysConstents;
public class UIUtil {
	public static void initGlobalFont(){
		//设置各个组件的字体
	    FontUIResource fontUIResource = new FontUIResource(SysConstents.DEFAULT_FONT);
	    //
	    for (Enumeration keys = UIManager.getDefaults().keys(); 
	    		keys.hasMoreElements();) {
	        Object key = keys.nextElement();
	        Object value= UIManager.get(key);
	        if (value instanceof FontUIResource) {
	            UIManager.put(key, fontUIResource);
	        }  
	    }
	}
}

连接数据库

package cn.com.jdbc;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

/**
* @ClassName: JdbcUtils_DBCP
* @Description: 数据库连接工具类
* @author: 命运的信徒
* @date: 2018-10-13 
*
*/ 
public class JdbcUtils_DBCP {
    /**
     * 在java中,编写数据库连接池需实现java.sql.DataSource接口,每一种数据库连接池都是DataSource接口的实现
     * DBCP连接池就是java.sql.DataSource接口的一个具体实现
     */
    private static DataSource ds = null;
    //在静态代码块中创建数据库连接池
    static{
        try{
            //加载dbcpconfig.properties配置文件
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties prop = new Properties();
            prop.load(in);
            //创建数据源
            ds = BasicDataSourceFactory.createDataSource(prop);
        }catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    
    /**
    * @ClassName: JdbcUtils_DBCP
    * @Description: 数据库连接工具类
    * @author: 命运的信徒
    * @date: 2018-10-13 
    *
    */
    public static Connection getConnection() throws SQLException{
        //从数据源中获取数据库连接
        return ds.getConnection();
    }
    
    /**
    * @Method: release
    * @Description: 释放资源,
    * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
    * @param conn
    * @param st
    * @param rs
    */
    public static void release(Connection conn,Statement st,ResultSet rs){
        if(rs!=null){
            try{
                //关闭存储查询结果的ResultSet对象
                rs.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if(st!=null){
            try{
                //关闭负责执行SQL命令的Statement对象
                st.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        if(conn!=null){
            try{
                //将Connection连接对象还给数据库连接池
                conn.close();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 

package cn.com.test;
import java.awt.BorderLayout;
import java.awt.TextArea;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import tanling.matplot_4j.comment.SysConstents;
import tanling.matplot_4j.d3d.facade.MatPlot3DMgr;
import tanling.matplot_4j.style.ColorHelper;
public abstract class AbsContentPanel extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	//公用一个窗口
	protected Test demoFrame;
	//选项卡面板
	protected JTabbedPane tab = new JTabbedPane();
	//选择面板
	protected OptionPanel optionPanel;
	//显示面板(这个很重要,如果没有这个的话就显示不出来画面)
	protected JPanel showPanel;
	//文本框
	protected TextArea textArea = new TextArea();
	// 三维空间数据
	protected MatPlot3DMgr mgr = new MatPlot3DMgr();
	//仪表板
	public AbsContentPanel(Test frame, String tabName) {
		this.demoFrame=frame;		
		this.setLayout(new BorderLayout());
		this.add(tab, BorderLayout.CENTER);		
		this.optionPanel = new OptionPanel(this);
		//添加一个观察者,前提是这个观察者已经在观察对象里面
		mgr.addObserver(optionPanel);
		//设置字体
		tab.setFont(SysConstents.DEFAULT_FONT);
		//初始化
		init();
		//显示面板
		this.showPanel = mgr.getPanel();
		//设置这个面板的边界
		 showPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2,
		 2, 2, 1), BorderFactory.createLineBorder(ColorHelper.LIGHT_BLUE)));
        //设置这个面板的布局格式为边界布局
		JPanel buffer = new JPanel(new BorderLayout());
		//二维趋势图显示在中间
		buffer.add(showPanel,BorderLayout.CENTER);
		//控制按钮面板显示在西边
		buffer.add(optionPanel,BorderLayout.EAST);
         //布局策略是固定布局
		tab.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
	    //给面板添加名称
		tab.addTab(tabName, buffer);

	}

	public abstract void init();
    //get方法
	public MatPlot3DMgr getMatPlot3DMgr() {
		return mgr;
	}
	public OptionPanel getOptionPanel() {
		return optionPanel;
	}
	public Test getTest() {
		return demoFrame;
	}

}
package cn.com.test;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import tanling.matplot4j.demo.TextFileHelper;
import tanling.matplot_4j.d3d.facade.MatPlot3DMgr;
public class Curves2DContentPanel extends AbsContentPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static String name = "GPS2";
	static String rq = "2019-02-12";
	// 构造方法
	public Curves2DContentPanel(Test frame) {
		super(frame, "二维折线图");
	}
	//
	public void init() {
		// 设置数据输入类型是二维折线类型
		mgr.setDataInputType(MatPlot3DMgr.DATA_TYPE_CURVE2DS);
		// 1.查询数据库里面的数据显示在页面上面
		// 用给定的x和y坐标来创建一个Point2D对象
		List<Point2D.Double> li1 = new ArrayList<Point2D.Double>();
		List<Point2D.Double> li2 = new ArrayList<Point2D.Double>();
		List<Point2D.Double> li3 = new ArrayList<Point2D.Double>();
		// 1.执行方法
		Displacement.selectPlace(name, rq);
		// 获取数组
		List<String> listx = Displacement.listx;
		List<String> listy = Displacement.listy;
		List<String> listh = Displacement.listh;
		double i = 0;
		for (String x : listx) {
			// string类型转换为float类型
			double d = Double.parseDouble(x);
			if ("GPS1".equals(name)) {
				d = d - 3426743.5691;
			} 			
			else if ("GPS2".equals(name)) {
				d = d - 3426378.816;
			} 
			else if ("GPS3".equals(name)) {
				d = d - 3426417.5292;
			} 
			else if ("GPS4".equals(name)) {
				d = d - 3426726.9758;
			} 
			else if ("GPSJZ".equals(name)) {
				d = d - 3426591.5880;
			}
			// String类型转换为double类型
			li1.add(new Point2D.Double(i,d));
			i = i+1;
		}
		i = 0;
		for (String x : listy) {
			// string类型转换为float类型
			double d = Double.parseDouble(x);
			if ("GPS1".equals(name)) {
				d = d - 196810.6433;
			}			
			else if ("GPS2".equals(name)) {
				d = d - 197154.6570;
			} 
			else if ("GPS3".equals(name)) {
				d = d - 197292.1969;
			}
			else if ("GPS4".equals(name)) {
				d = d - 197353.6056;
			}
			else if ("GPSJZ".equals(name)) {
				d = d - 196884.2600;
			}
			li2.add(new Point2D.Double(i, d));
			i = i+1;
		}
		i = 0;
		for (String x : listh) {
			// string类型转换为float类型
			double d = Double.parseDouble(x);
			if ("GPS1".equals(name)) {
				d = d + 28.4092;
			} 
			
			else if ("GPS2".equals(name)) {
				d = d + 56.3412;
			} 
			else if ("GPS3".equals(name)) {
				d = d + 53.8907;
			}
			
			else if ("GPS4".equals(name)) {
				d = d - 52.5174;
			} 
			else if ("GPSJZ".equals(name)) {
				d = d + 35.8728;
			}
			li3.add(new Point2D.Double(i, d));
			i = i+1;
		}
		i = 0;
		mgr.addData2D("Item1", null, li1);
		mgr.addData2D("Item2", null, li1);
		mgr.addData2D("Item3", null, li3);
		// 设置伸缩的y轴的比列
		mgr.setScaleY(1.5);
		// 设置视线俯仰角度
		mgr.setSeeta(0.15);
		// 获取视线方位角度
		mgr.setBeita(1.1);
		// 设置区域的
		this.textArea.setText(TextFileHelper
				.getText("demo_src_txt/Curver2dsDemoSrc.txt"));

	}

}
package cn.com.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import cn.com.jdbc.JdbcUtils_DBCP;
public class Displacement {
	static List<String> listx = null;
	static List<String> listy = null;
	static List<String> listh = null;
	private static Connection conn = null;
	private static PreparedStatement st = null;
	private static ResultSet rs = null;
	public static void selectPlace(String address, String rq) {
		listx=new ArrayList<String>();
		listy=new ArrayList<String>();
		listh=new ArrayList<String>();
		// 1.根据地址、当天的日期、和标准量,来计算偏移量
		SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd");
		// 2.查询数据库里当天的所有位移量
		String sql = "select * from port where StationName=? and StartTime like ? order by StartTime asc";
		rq = rq + " %";
		String[] str = new String[] { address, rq };
		try {
			// 获取数据库连接
			// 获取数据库连接
			conn = JdbcUtils_DBCP.getConnection();
			st = conn.prepareStatement(sql);
			if (str != null) {
				for (int i = 0; i < str.length; i++) {
					st.setString(i + 1, str[i]);
				}
			}
			rs = st.executeQuery();
			while (rs.next()) {
				// 1.x y 三个集合
				listx.add(rs.getString(8));
				listy.add(rs.getString(9));
				listh.add(rs.getString(10));
			}
		} catch (SQLException e) {
			e.getStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (st != null) {
					st.close();
				}
				if (conn != null) {
					conn.close();
				}

			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}
package cn.com.test;
import java.awt.CardLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class MainPanel extends JPanel {
	//设置二维为3
	public static final int CURVES_PLANE=3;	
	//面板
	private Test demoFrame;		
	//曲面2d中心面板
	private Curves2DContentPanel curves2DContentPanel;	
	//设置卡片布局管理器
	private CardLayout card=new CardLayout();
	//
	private List<AbsContentPanel> contentPanels=new ArrayList<AbsContentPanel>();
	//构造方法
	public MainPanel(Test demoFrame){
		this.demoFrame= demoFrame;
		this.setLayout(card);
		//二维曲线内容面板
		this.curves2DContentPanel=new Curves2DContentPanel(demoFrame);
		//添加
		this.add(curves2DContentPanel,CURVES_PLANE+"");
		//
		contentPanels.add(curves2DContentPanel);		
	}	
	//设置类型
	public void setType(int type){		
		this.card.show(this, type+"");
	}
	//设置是否锯齿
	public void setGlobalAntiAliasing(boolean b){
		for(int i=0;i<this.contentPanels.size();i++){
			contentPanels.get(i).getOptionPanel().setAntiAliasing(b);
			contentPanels.get(i).getMatPlot3DMgr().setAntiAliasing(b);
		}
	}

	
	
	public void setGlobalMouseDraggable(boolean b){
		for(int i=0;i<this.contentPanels.size();i++){
			contentPanels.get(i).getOptionPanel().setMouseDraggable(b);
			contentPanels.get(i).getMatPlot3DMgr().setMouseDraggable(b);
		}
	}
}
package cn.com.test;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import tanling.matplot_4j.comment.SysConstents;
import tanling.matplot_4j.d3d.base.speg.Point3D;
import tanling.matplot_4j.d3d.facade.MatPlot3DMgr;
import tanling.matplot_4j.style.ColorHelper;
public class OptionPanel extends JPanel implements Observer {
	private boolean isAntiAliasing = false;
	private boolean isMouseDraggable = true;
	private double seeta;
	private double beita;
	private double unitX;
	private double unitY;
	private double unitZ;
	private double scaleX;
	private double scaleY;
	private double scaleZ;
	private Point3D focusPoint = new Point3D(0, 0, 0);
	private boolean isFocusPerspective = true;
	private int rGap = 6;
	private int rHeigth = 19;
	private int xBorder = 12;
	private int yBorder = 26;
	private int[] vWidths = new int[] { 105, 173, 150 };
	private JCheckBox checkAntiAliasing = new JCheckBox("AntiAliasing");
	private JCheckBox checkMouseDraggable = new JCheckBox("MouseDraggable");
	private JCheckBox checkShowReferencePlanes = new JCheckBox(
			"ShowReferencePlanes");
	private JRadioButton raScatterPerspective = new JRadioButton(
			"ScatterPerspective");
	private JRadioButton raFocusPerspective = new JRadioButton(
			"FocusPerspective");
	private JTextField seetaTextField = new JTextField();
	private JTextField beitaTextField = new JTextField();
	private JTextField scaleXTextField = new JTextField();
	private JTextField scaleYTextField = new JTextField();
	private JTextField scaleZTextField = new JTextField();
	private AbsContentPanel holder;

	public OptionPanel(AbsContentPanel holder) {
		this.holder = holder;
		this.setLayout(null);
		this.setBackground(Color.WHITE);
		this.setPreferredSize(new Dimension(300, 800));
		this.setBorder(BorderFactory.createTitledBorder(
				BorderFactory.createLineBorder(ColorHelper.LIGHT_BLUE),
				"Observation parameters"));
		ButtonGroup bg = new ButtonGroup();
		bg.add(this.raFocusPerspective);
		bg.add(this.raScatterPerspective);
		raFocusPerspective.setSelected(true);

		this.add(checkAntiAliasing, 0, 0, 1, 2);
		this.add(checkMouseDraggable, 1, 0, 1, 2);
		checkMouseDraggable.setSelected(true);

		this.add(raFocusPerspective, 3, 0, 1, 2);
		this.add(raScatterPerspective, 4, 0, 1, 2);

		this.add(new JLabel("seeta"), 6, 0);
		this.add(seetaTextField, 6, 1);

		this.add(new JLabel("beita"), 7, 0);
		this.add(beitaTextField, 7, 1);

		this.add(new JLabel("scaleX"), 9, 0);
		this.add(scaleXTextField, 9, 1);

		this.add(new JLabel("scaleY"), 10, 0);
		this.add(scaleYTextField, 10, 1);

		this.add(new JLabel("scaleZ"), 11, 0);
		this.add(scaleZTextField, 11, 1);

		this.add(checkShowReferencePlanes, 13, 0, 1, 2);
		checkShowReferencePlanes.setSelected(true);

		initListener();

	}

	private void initListener() {

		this.checkMouseDraggable.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				holder.getTest()
						.getMainPanel()
						.setGlobalMouseDraggable(
								checkMouseDraggable.isSelected());

			}
		});

		this.checkAntiAliasing.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				holder.getTest().getMainPanel()
						.setGlobalAntiAliasing(checkAntiAliasing.isSelected());

				try {

					holder.mgr.updateView(2);

				} catch (InterruptedException e1) {

				}
			}
		});

		this.checkShowReferencePlanes.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				holder.mgr.setShowReferencePlanes(checkShowReferencePlanes
						.isSelected());
				try {
					holder.mgr.updateView(2);
				} catch (InterruptedException e1) {
				}
			}
		});

		raScatterPerspective.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				holder.mgr.setScatterPerspectiveType(true);

				try {
					holder.mgr.updateView(2);
				} catch (InterruptedException e1) {
				}
			}
		});

		raFocusPerspective.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				holder.mgr.setFocusPerspectiveType(true);

				try {
					holder.mgr.updateView(2);
				} catch (InterruptedException e1) {
				}
			}
		});

		seetaTextField.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				try {
					double d = Double.valueOf(seetaTextField.getText());
					holder.mgr.setSeeta(d);
					holder.mgr.updateView(2);
				} catch (Exception ex) {
				}
			}
		});

		beitaTextField.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				try {
					double d = Double.valueOf(beitaTextField.getText());
					holder.mgr.setBeita(d);
					holder.mgr.updateView(2);
				} catch (Exception ex) {
				}
			}
		});

		scaleXTextField.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				try {
					double d = Double.valueOf(scaleXTextField.getText());
					holder.mgr.setScaleX(d);
					holder.mgr.updateView(2);
				} catch (Exception ex) {
				}
			}
		});

		scaleYTextField.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				try {
					double d = Double.valueOf(scaleYTextField.getText());
					holder.mgr.setScaleY(d);
					holder.mgr.updateView(2);
				} catch (Exception ex) {
				}
			}
		});

		scaleZTextField.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				try {
					double d = Double.valueOf(scaleZTextField.getText());
					holder.mgr.setScaleZ(d);
					holder.mgr.updateView(2);
				} catch (Exception ex) {
				}
			}
		});

	}

	public void add(JComponent comp, int r, int c) {

		add(comp, r, c, 1, 1);
	}

	public void add(JComponent comp, int r, int c, int spanRow, int SpanColumn) {

		this.add(comp);
		comp.setFont(SysConstents.TEXT_FONT);
		comp.setBackground(Color.WHITE);
		comp.setBorder(BorderFactory.createEmptyBorder());

		int y = r * (rHeigth + rGap) + yBorder;

		int x = 0;

		if (c <= 0) {
			x = xBorder;
		} else {
			x = this.vWidths[c - 1] + xBorder;
		}

		int width = 0;

		for (int b = c, i = 0; i < SpanColumn; i++) {
			width += vWidths[i];
		}

		int heigth = this.rHeigth * spanRow + this.rGap * (spanRow - 1);

		comp.setBounds(x, y, width, heigth);
	}

	private void updateSelf() {
		this.beitaTextField.setText(String.format("%.2f", this.beita));
		this.seetaTextField.setText(String.format("%.2f", this.seeta));

		this.scaleXTextField.setText(String.format("%.2f", this.scaleX));
		this.scaleYTextField.setText(String.format("%.2f", this.scaleY));
		this.scaleZTextField.setText(String.format("%.2f", this.scaleZ));

	}

	private void updateView(MatPlot3DMgr mgr) {

		this.beita = mgr.getBeita();
		this.seeta = mgr.getSeeta();

		this.scaleX = mgr.getScaleX();
		this.scaleY = mgr.getScaleY();
		this.scaleZ = mgr.getScaleZ();

		this.unitX = mgr.getUnitX();
		this.unitY = mgr.getUnitX();
		this.unitZ = mgr.getUnitX();

		updateSelf();

	}

	public void update(Observable o, Object arg) {
		MatPlot3DMgr mgr = (MatPlot3DMgr) o;
		updateView(mgr);
	}

	public boolean isAntiAliasing() {
		return isAntiAliasing;
	}

	public void setAntiAliasing(boolean isAntiAliasing) {
		this.isAntiAliasing = isAntiAliasing;
		this.checkAntiAliasing.setSelected(isAntiAliasing);
	}

	public boolean isMouseDraggable() {
		return isMouseDraggable;
	}

	public void setMouseDraggable(boolean isMouseDraggable) {
		this.isMouseDraggable = isMouseDraggable;
		this.checkMouseDraggable.setSelected(isMouseDraggable);
	}

	public static void main(String[] args) {
		JFrame jf = new JFrame("力凡公司");
		OptionPanel p = new OptionPanel(null);
		jf.setContentPane(p);
		jf.setDefaultCloseOperation(jf.EXIT_ON_CLOSE);
		jf.setSize(1000, 800);
		jf.setVisible(true);

	}
}
package cn.com.test;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test extends JFrame {	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private MainPanel mainPanel;
	public Test(String title) {
		super(title);
		this.mainPanel=new MainPanel(this);		
		JPanel contentPanel=new JPanel();
		contentPanel.setLayout(new BorderLayout());
		this.setContentPane(contentPanel);		
		mainPanel.setType(MainPanel.CURVES_PLANE);
		contentPanel.add(mainPanel,BorderLayout.CENTER);
	}

	public MainPanel getMainPanel() {
		return mainPanel;
	}
	
	public static void main(String[] args) {		
		Test jf = new Test("小栗子");			
		try {			
			SwingUtilities.updateComponentTreeUI(jf);
		} catch (Exception e) {
			e.printStackTrace();
		}

		jf.setDefaultCloseOperation(jf.EXIT_ON_CLOSE);
		jf.setSize(1300, 820);
		jf.setVisible(true);
		
		
	}	
}

想要知道如何更改jar包里面的源代码么?

https://blog.csdn.net/qq_37591637/article/details/87854553

 

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qq_37591637

请给我持续更新的动力~~

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

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

打赏作者

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

抵扣说明:

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

余额充值