javaweb项目

3 篇文章 0 订阅
3 篇文章 0 订阅
本文详细介绍了使用Java Web进行MiniUI界面开发的各种组件应用,包括按钮、列表、表单、下拉框、时间选择器等,并展示了数据库连接配置、通用查询和更新操作。此外,还涵盖了字符编码过滤器、页面加载、数据联动及删除操作的实现,提供了完整的代码示例和页面配置。
摘要由CSDN通过智能技术生成

项目准备

代码结构

image-20211127075358484

image-20211127075422723

数据库配置文件

jdbc.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/[数据库名]?rewriteBatchedStatements=true
username=root
password=Gepoint
initialSize=10
maxActive=20
maxWait=1000
filters=wall

工具类

StringUtil

/**
     *[ 判断字符串是否为空]
     * 
     * @param str
     * @return
     */
    public static boolean isBlank(String str) {
        boolean result = false;
        if (str == null || "".equals(str) || str.trim().length() == 0) {
            result = true;
        }
        return result;
    }

    /**
     * [判断字符串是否非空]
     * 
     * @param str
     * @return
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    /**
     *[ 将list的内容以分隔符的形式拼接到字符串]
     * 
     * @param list
     * @param div
     *            分隔符
     * @return
     */
    public static String joinListToString(List<String> list, String div) {

        StringBuffer sb = new StringBuffer();
        for (String str : list) {
            sb.append(str).append(div);
        }
        return sb.toString().substring(0, sb.length() - div.length());
    }

JDBCUtil

/**
 * [负责获取和关闭数据库连接]
 * 
 * @author houjiahui
 *
 */
public class JDBCUtil
{



    /**
     * [ 获取数据库连接对象]
     * 
     * @return
     * @throws SQLException
     */
    public static Connection getDruidConnecton() {
        Connection conn = null;
        try {
            conn = DSUtil.getDruidDataSource().getConnection();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * [关闭ResultSet,PreparedStatement,Connection对象]
     * 
     * @param rs
     * @param ps
     * @param conn
     */
    public static void CloseConnection(ResultSet rs, PreparedStatement ps, Connection conn) {

        if (rs != null) {
            try {
                rs.close();
            }
            catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            }
            catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            }
            catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

DSUtil

public class DSUtil
{
    // 配置静态数据库连接池
    private static DataSource ds;

    /**
     * [获取连接池对象]
     * @return
     */
    public static DataSource getDruidDataSource() {
        try {
            Properties pro = new Properties();
            pro.load(JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"));
            ds = DruidDataSourceFactory.createDataSource(pro);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return ds;
    }
}

DBUtils

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * [负责一些通用的增删改查操作]
 * 
 * @author houjiahui
 *
 */
public class DBUtils
{

    /**
     * [通用的查询操作]
     * @param connection 用于事务操作
     * @param clazz 传入实例类
     * @param sql
     * @param args
     * @return 查多条就直接返回,查单条就get(0)
     */
    public static <T> List<T> getInstance(Connection connection, Class<T> clazz, String sql, Object... args) {
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        ArrayList<T> arr = new ArrayList<>();
        try {
            preparedStatement = connection.prepareStatement(sql);
            // 填充占位符
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            // 获取结果集列数,封装在元数据中
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 通过resultSetMetaData获取结果集列数
            int columnCount = metaData.getColumnCount();
            while (resultSet.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    // 获取列的值
                    Object value = resultSet.getObject(i + 1);
                    // 获取列名
                    String columnName = metaData.getColumnLabel(i + 1);
                    // System.out.println(columnName);
                    // 加载运行时类的属性
                    Field field = clazz.getDeclaredField(columnName);
                    // 保证属性可访问
                    field.setAccessible(true);
                    field.set(t, value);
                }
                arr.add(t);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            JDBCUtil.CloseConnection(resultSet, preparedStatement, null);
        }
        return arr;
    }

    /**
     * [通用的增、删、改操作,带事务处理]
     * 
     * @param sql
     * @param args
     */
    public int update(Connection connection, String sql, Object... args) {
        PreparedStatement ps = null;
        int c = 0;
        try {
            // 获取PreparedStatement的实例
            ps = connection.prepareStatement(sql);
            // 填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            // 执行sql语句
            c = ps.executeUpdate();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            // 关闭资源
            JDBCUtil.CloseConnection(null, ps, null);
        }
        return c;
    }

}

所需的pom文件

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>


    </dependencies>


    <build>
        <plugins>
            <!-- 控制编译版本(否则每次工程update的时候,编译版本都会恢复到1.5 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <!-- tomcat插件配置 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8099</port>
                </configuration>
            </plugin>
        </plugins>
    </build>

处理字符编码的过滤器

EncodingFilter

@WebFilter("/*")

        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);

所需的miniui资源文件

image-20211127081147419

image-20211127081155545

项目创建

image-20211127081420327

image-20211127081443140

image-20211127081519774

image-20211127081554297

image-20211127081632721

miniui

通用

按钮

<a class="mini-button" onclick="search()">查询</a>

拼串

'<a class="mini-button" onclick="editBookInfo(\''+bookid+'\')">编辑</a>'

列表

表单

下拉框mini-combobox

注意valueField和textField映射的值,数据加载地址可以写文件也可以发送请求

<input id="bookTypeSearch" name="bookTypeSearch" emptyText="请输入图书类别" class="mini-combobox" showNullItem="true" allowInput="true" nullItemText="--请选择类别--" url="../../data/booktype.txt" textField="text" valueField="id" />

请求文件格式

[
    { "id": "1", "text": "文学类" },
    { "id": "2", "text": "科技类" },
    { "id": "3", "text": "艺术类" },
    { "id": "4", "text": "其他类" }
]

文本输入框textbox

<input name="bookname" class="mini-textbox" required="true" emptyText="请输入图书名称" requiredErrorText="你忘记输入图书名称了" />

点选数字spinner

<input name="remain" class="mini-spinner" value="10" minValue="1" maxValue="200" />

时间datepicker

一定要记得格式化

前台

<input id="borrowtime" class="mini-datepicker" style="width: 200px" onvaluechanged="onValueChanged" nullValue="null" format="yyyy-MM-dd H:mm:ss" timeFormat="H:mm:ss" showTime="true" showOkButton="true" showClearButton="false" allowInput="false"/>

后台

        HashMap<String, Object> hashMap = new HashMap<String, Object>();
        hashMap.put("total", total);
        hashMap.put("data", borrowllist);        
		String json = JSONObject.toJSONStringWithDateFormat(hashMap, "yyyy-MM-dd HH:mm:ss");
        response.getWriter().write(json);

单选radiobuttonlist

                        <input id="country" name="country" class="mini-radiobuttonlist"
                            url="../../data/countrys.txt" textField="text" valueField="id" />

典型页面

1.OutlookMenu

主要修改折叠菜单和iframe的指向

image-20211127082255581

欢迎页面的指向

image-20211127082532967

左侧菜单布局和指向

image-20211127082607215

菜单配置文件

[
    { id: "bookinfo", text: "图书信息管理", iconCls: "icon-folder"},
    { id: "addBookinfo", pid: "bookinfo", text: "图书列表", iconCls: "icon-add", url: "./pages/bookinfo/bookinfolist.html" },

    { id: "borrowinfo", text: "借阅信息管理", iconCls: "icon-folder"},
    { id: "addBorrowinfo", pid: "borrowinfo", text: "借阅列表", iconCls: "icon-add", url: "./pages/borrowinfo/borrowinfolist.html" },
]

2.新增页面

image-20211127093342464

典型事件

开始的表格数据加载(带排序的)

可以加上keywords来实现关键字查询

需要四个参数(pageIndex, pageSize, sortField, sortOrder)

前台需要的设置:

grid.sortBy("borrowtime", "desc");

或者在div中加属性:

    <div id="datagrid1" class="mini-datagrid" style="width: 100%; height: 100%" allowResize="false"
      url="../../borrowinfolistaction?method=queryborrowinfo" idField="id" multiSelect="true" sizeList="[5,10,20,50]"
      pageSize="10" sortField="borrowtime" sortOrser="desc">
        <!--表格内容-->
	</div>

注意前后台传值的大小写对应

渲染列表项目

image-20211127090457393

renderer="onxxxRenderer"
    //获取类别选项
    function getBookTypeData() {
      $.ajax({
        url: "../../data/booktype.txt",
        success: function (text) {
          // 解析成object对象
          bookType = mini.decode(text);
        },
        error: function () {
        }
      });
    }

    // 渲染图书类别
    function onBookTypeRenderer(e) {
      for (var i = 0, l = bookType.length; i < l; i++) {
        var type = bookType[i];
        if (type.id == e.value) {
          return type.text;
        }
      }
      return "";
    }

渲染css样式

    //渲染css样式,当前行remain颜色和背景色
    function onRemainRenderer(e) {
      var remain = e.value;
      if (remain < 10) {
        //设置字体样式
        e.cellStyle = "font-weight:bold;color:red;";
        //设置行样式
        e.rowStyle = "background-color:yellow;";
      }
      //设置完格式之后要返回,不知道展示什么信息
      return e.value;
    }

清空列表

//清空列表
function clearForm() {
  var bookname = mini.get("bookNameSearch").setValue("");
  var booktype = mini.get("bookTypeSearch").setValue("");
  grid.load();
}

关键字查询

grid.load可以向服务器传数据

    function search() {
      var bookname = mini.get("bookNameSearch").getValue();
      var booktype = mini.get("bookTypeSearch").getValue();

      //这里会调用url="../../bookinfolistaction?method=queryBookinfoByKeyWords"
      //load方法可以向服务器传数据,服务器端可以接受请求参数(key:value)
      grid.load({ bookname: bookname, booktype: booktype });
    }

对应的后台方法

需要的参数

  • pageIndex—默认第一页为0
  • pageSize—可以自行设置
  • 自己设置的keywords,如:bookname,booktype

对应的dao方法:

//判断字符是否为空,用StringBuffer来进行sql的拼接
//
public List<BookInfo> queryBookinfoByKeyWords(int pageIndex, int pageSize, String bookname, Integer booktype);

主要片段:

        StringBuffer sb = new StringBuffer();
        sb.append(" select * from bookinfo where 1=1 ");

        if (StringUtil.isNotBlank(bookname)) {
            sb.append(" and bookname like concat('%', ? ,'%') ");
        }
        if (booktype != null) {
            sb.append(" and booktype = ? ");
        }
        sb.append(" limit ?,?");

        String sql = sb.toString();
        int i = 1;
        try {
            ps = con.prepareStatement(sql);
            if (StringUtil.isNotBlank(bookname)) {
                ps.setString(i++, bookname);
            }
            if (booktype != null) {
                ps.setInt(i++, booktype);
            }
            ps.setInt(i++, indexnum);
            ps.setInt(i++, pageSize);

新增操作(弹出)

    //新增图书页
    function add() {
      mini.open({
        url: bootPATH + "../pages/bookinfo/bookinfoadd.html",
        title: "新增图书信息",
        width: 600,
        height: 400,
        onload: function () {
          var iframe = this.getIFrameEl();
          var data = { action: "new" };
          iframe.contentWindow.SetData(data);
        },
        ondestroy: function (action) {
          grid.reload();
        }
      });
    }

编辑页面设置初始数据

    //标准方法接口定义
    //加载编辑页面的时候默认填充数据
    function SetData(data) {
      //跨页面传递的数据对象,克隆后才可以安全使用
      data = mini.clone(data);
      $.ajax({
        url:
          "../../bookinfoeditaction?method=queryBookInfoByID&bookId=" +
          data.bookId,
        cache: false,
        success: function (text) {
          var o = mini.decode(text);
          form.setData(o);
          form.setChanged(false); //设置当前表单未修改的状态
        },
        error: function () {
        	alert("表单加载错误");
		}
      });
    }

数据修改未保存的操作

    //改变较多,参考原生代码修改,运用miniui自己的弹窗提示
    //点击取消按钮的时候进行的操作
    function onCancel(e) {
      //表单被改变的操作
      if (form.isChanged()) {
        mini.confirm(
          "数据被修改了,是否先保存?",
          "提醒:",
          function (action) {
            //console.log(action);
            //["ok", "no", "cancel"]
            if (action == "ok") {
              //点击确定就保存数据
              SaveData();
            } else {
              //点击取消就关闭窗口
              CloseWindow("cancel");
            }
          }
        );
      } else {
        //数据未被修改的操作
        CloseWindow("cancel");
      }
    }

详情页渲染(利用修改页面)

    labelModel();

    //渲染只读模式
    function labelModel() {
      var fields = form.getFields();
      for (var i = 0, l = fields.length; i < l; i++) {
        var c = fields[i];
        if (c.setReadOnly) c.setReadOnly(true); //只读
        if (c.setIsValid) c.setIsValid(true); //去除错误提示
        if (c.addCls) c.addCls("asLabel"); //增加asLabel外观
      }
    }
  <style type="text/css">
    html,
    body {
      padding: 0 5px;
      margin: 0;
      border: 0;
      height: 100%;
      overflow: hidden;
    }

    .asLabel .mini-textbox-border,
    .asLabel .mini-textbox-input,
    .asLabel .mini-buttonedit-border,
    .asLabel .mini-buttonedit-input,
    .asLabel .mini-textboxlist-border {
      border: 0;
      background: none;
      cursor: default;
    }

    .asLabel .mini-buttonedit-button,
    .asLabel .mini-textboxlist-close {
      display: none;
    }

    .asLabel .mini-textboxlist-item {
      padding-right: 8px;
    }
  </style>

动态按钮渲染

image-20211127104956922

    //渲染操作按钮
    function onOptionButtonRenderer(e) {
      var borrowid = e.row.borrowid;
      var returntime = e.row.returntime;
      var str;
      var str1;
      str =
        '<a class="mini-button" οnclick="deleteBorrowInfo(\'' +
        borrowid +
        "')\">删除</a>";
      str1 =
        '<a class="mini-button" οnclick="returnBook(\'' +
        borrowid +
        "')\">还书</a>";

      if (returntime) {
        return str;
      } else {
        return str1;
      }
    }

自动生成编号

数据库生成

select concat('Borrow',year(now()),lpad(right(ifnull(max(b.borrowid),0) ,4)+1,4,0)) from borrowinfo b
where mid(borrowid,7,4)=year(now()); 
    setFormValue();
	//新增时自动生成borrowid
    function setFormValue() {
      $.ajax({
        url: "../../borrowinfoaddaction?method=getnextborrowid",
        type: "post",
        cache: false,
        success: function (text) {
          //设置借阅编号
          mini.get("borrowid").setValue(text);
          //设置借阅时间
          mini.get("borrowtime").setValue(new Date());
        },
        error: function (jqXHR, textStatus, errorThrown) {
          alert(jqXHR.responseText);
          mini.alert(textStatus, "提示:", function () {
            CloseWindow();
          }); 
        }

      });
    }

数据联动

//数据联动用onvalueChanged,当下拉框改变的时候,输入框自动写入剩余数量
    function onBookIdChanged(e) {
      //方法2:简便
      //var remain = e.selected.remian;

      var bookId = e.value;

      $.ajax({
        url:
          "../../bookinfolistaction?method=queryreaminbybookid&bookid=" +
          bookId,
        type: "post",
        cache: false,
        success: function (text) {
          mini.get("remain").setValue(text);
        },
        error: function (jqXHR, textStatus, errorThrown) {
          alert(jqXHR.responseText);
          mini.alert(textStatus, "提示:", function () {
            CloseWindow();
          }); 
        }
      });
    }

行内点击时填充相应数据

image-20211127113431277

    //图书借阅页面
    function borrowBookInfo(bookId) {
      mini.open({
        url: bootPATH + "../pages/borrowinfo/borrowinfoadd.html",
        title: "图书借阅",
        width: 600,
        height: 400,
        onload: function () {
          var iframe = this.getIFrameEl();
          var data = { bookId: bookId, action: "listButton" };
          iframe.contentWindow.SetData(data);
        },
        ondestroy: function (action) {
          grid.reload();
        }
      });
    }
//当行内点击时候才会填充数据,bookinfolist来调用的
function SetData(data) {
  if (data.action == "listButton") {
    //跨页面传递的数据对象,克隆后才可以安全使用
    data = mini.clone(data);
    var bookId = data.bookId;

    $.ajax({
      url:
        "../../borrowinfoaddaction?method=getbookbyid&bookid=" + bookId,
      cache: false,
      success: function (text) {
        var o = mini.decode(text);
        mini.getbyName("bookid").setValue(o.bookid);
        mini.getbyName("bookid").setText(o.bookname);
        mini.getbyName("bookid").setEnabled(false);
        mini.getbyName("remain").setValue(o.remain);
      },
      error: function (jqXHR, textStatus, errorThrown) {
        alert(jqXHR.responseText);
        mini.alert(textStatus, "提示:", function () {
          CloseWindow();
        }); 
      }
    });
  }
}

删除操作(单选+多选)

image-20211127115327316

删除的时候进行提示,确定则删除

将选择的id封装程 aa,bb,cc的数组传到后台

      //单选+多选删除数据
    function deleteBookInfo() {
      var rows = grid.getSelecteds();
      if (rows.length > 0) {
        mini.confirm("确定删除选中记录?", "提示信息:", function (action) {
          if (action == "ok") {
            var ids = [];
            for (var i = 0, l = rows.length; i < l; i++) {
              var r = rows[i];
              ids.push(r.bookid);
            }
            var bookids = ids.join(",");
            grid.loading("操作中,请稍后......");
            $.ajax({
              url:
                "../../bookinfolistaction?method=deletebookinfo&bookids=" +
                bookids,
              success: function (text) {
                      mini.alert(text);
                      grid.reload();
              },
              error: function () {
              }
            });
          }
        });
      } else {
        mini.alert("请选中一条记录!");
      }
    }

后台解析并级联删除

级联操作示例:

dao层

		int i = 0;//记录操作a成功条数
        int j = 0;//记录操作b成功条数
        int result = 0;//记录a,b都成功的条数,当都成功时候才会提交        

		String sql = " DELETE FROM bookinfo WHERE bookid=? ";
        String sql2 = "delete from borrowinfo where bookid=?";
		connection.setAutoCommit(false);
		//直接级联操作,
		//失败就回滚
		//成功就提交
		

service层

        ArrayList<String> deleteSuccess = new ArrayList<String>();
        ArrayList<String> deleteFail = new ArrayList<String>();
        ArrayList<String> deleteError = new ArrayList<String>();
		String[] split = bookIds.split(",");
        for (String bookid : split) {......}
        //利用工具类进行拼串
        StringBuffer result = new StringBuffer();
		....
        return result.toString();

接口定义

dao层

bookinfo


public int addBookInfo(BookInfo bookInfo);
public int updateBookInfo(BookInfo bookInfo);
public int deleteBookinfo(String bookIds);
public int deleteBookinfoById(String bookId);
public BookInfo queryBookInfoByID(String bookId);
public List<BookInfo> queryBookinfoByKeyWords(int pageIndex, int pageSize, String bookname, Integer booktype);
public int findLength();
public BookInfo checkExist(String booknamebefore, String booknamenow, String author);

borrowinfo

常见问题

时间格式获取的时候出现.0的情况

        String sql = "select * from borrowinfo ";
        List<BorrowInfo> bookInfos = getInstance(BorrowInfo.class, sql);
        // 处理时间后面有个.0的问题
        Date borrowtime = bookInfos.get(0).getBorrowtime();
        DateFormat dateTimeInstance = DateFormat.getDateTimeInstance();
        String format = dateTimeInstance.format(borrowtime);
        System.out.println(format);

时间格式设置获取

borrowInfo.setBorrowtime(rs.getTimestamp("borrowtime"));

prepareStatement.setObject(5, new Date());

前后台时间格式

要统一,见上面

数据格式对应

datetime–Timestamp

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaWeb项目是使用Java平台上的Web开发技术来构建的项目。它包含了一些关键的技术,如Servlet、JSP、JavaBean和JDBC等。其中,Servlet是JavaWeb中的一个组件,它用于处理HTTP请求和生成响应。JSP是另一个组件,它允许开发者在HTML页面中嵌入Java代码,以便动态生成页面。JavaBean是用于封装数据和业务逻辑的Java类。JDBC是Java提供的用于与数据库进行交互的API。 要创建一个JavaWeb项目,首先需要在开发环境中安装好Java开发工具,比如Eclipse或IntelliJ IDEA。然后按照以下步骤进行操作: 1. 打开Java开发工具,点击菜单中的“File”(文件)选项,选择“New”(新建)。 2. 在弹出的菜单中选择“Project”(项目)选项。 3. 在“New Project”(新建项目)窗口中,输入项目名称、项目所在路径和项目类型等信息。 4. 选择项目模板为“Web application”(Web应用程序)。 5. 选择刚刚配置的Tomcat作为项目的服务器。 6. 单击“Next”(下一步)按钮,按照向导完成项目的创建过程。 通过以上步骤,你就可以成功创建一个JavaWeb项目了。在项目中,你可以使用Servlet、JSP、JavaBean和JDBC等技术来实现你的业务逻辑,并且通过Tomcat服务器来部署和运行你的项目JavaWeb技术是指在Java平台上进行Web开发的一系列技术,包括Servlet、JSP、JavaBean和JDBC等。 JSP允许开发者在HTML页面中嵌入Java代码,以便动态生成页面。 创建JavaWeb项目时,需要指定项目名称、项目所在路径和项目类型等信息,并选择适当的模板和服务器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

迪杰斯特夫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值