【毕业设计】基于SSM的校园二手市场 网站设计与实现 - java web

293 篇文章 9 订阅
266 篇文章 18 订阅

前言

Hi,同学们好呀,学长今天带大家复盘一个学长帮往届同学做的一个毕业作品

基于Spring boot的校园二手市场网站设计与实现

2 项目背景

如今的大学校园中 随着大学生的购买能力的提高存在着两种局面。一是大学期间购买的收纳类、实用类物品,在毕业季大家面临带不走、不舍得扔的尴尬局面;二是购买的东西中越来越多的大家用不上的物品,这些物品成了大部分大学生的累赘。因此,低价卖掉这些仍可以继续利用的物品是一个两全其美的方法于是校园二手交易市场诞生了。

随着科技的迅速发展校园二手商品交易市场也不仅仅局限于校园内摆地摊的形式,大家更多的是使用手机线上购物,我们的项目就是基于这样的局面产生的,让同学们足不出户就可以淘到自己所需要的物美价廉的物品。

3 系统概述

校园二手交易网为用户提供了一个二手交易的平台。根据大中学校商品情况及学生的实际需求,系统的主要功能模块为信息分类、信息搜索、发布信息、用户注册登陆、管理后台等。在网站的设计中,分为前台和后台两个部分设计,前台主要用于提供用户注册和登陆、发布供求信息、查询供求信息、用户留言等功能,后台主要功能有用户管理、供求信息管理、信息分类管理、留言管理等。系统还可提供用户对自己发表的供求信息的删除,以及对用户信息的修改功能,可以方便用户对自己基本信息的管理。

在这里插入图片描述

4 系统功能描述

在这里插入图片描述

系统的使用者为系统管理员和用户,用户在系统注册后生成用户信息表文件。系统的功能分为两个模块,面向管理员的模块功能是系统管理,主要是删除系统非法用户的帐号信息;面向一般用户的模块功能是户信息管理和交易管理。其中,用户信息管理包括更改用户注册邮箱,更改用户密码,更改用户基本信息;交易管理包括出售管理,求购管理,买卖信息管理。

4.1 系统管理

在这里插入图片描述
管理员功能:对用户发出警告,从用户信息表中删除非法用户,这项功能只能为管理员所有。

4.2 用户管理

在这里插入图片描述
这个模块实现了用户请求交易,发布、更新交易信息的功能,并使用户能够更新自己的注册信息以及基本信息。

4.3 交易管理

在这里插入图片描述

在用户交易管理中,根据用户的提供的交易物品生成了“出售信息表”和“求购信息表”,用户可以随时对自发布的信息进行更改或删除。在交易的过程中,系统会根据这两个表生成对应物品的求购(出售)信息目录供用户浏览参考。对于没有明显求购或出售目标的用户,也可以浏览由求购、出售信息表生成的求购、出售物品目录。

4.4 订单管理

在这里插入图片描述

用户录入出售信息(包括出售物品名称,出售物品价格,出售物品种类,出售物品简单描述,联系电话,电子邮箱)。经用户检查录入信息正确无误,生成出售物品信息单。系统将出售信息纳入出售信息表,并根据出售信息表上的内容发布出售信息。

4.5 买卖信息更新管理

在这里插入图片描述
用户可以随时更改买卖信息。

4.5 搜索

在这里插入图片描述

5 系统实现效果

首页
在这里插入图片描述

登录/注册
在这里插入图片描述

分类
在这里插入图片描述
在这里插入图片描述

搜索
在这里插入图片描述

商品详情

在这里插入图片描述

评论
在这里插入图片描述

卖东西

在这里插入图片描述

用户中心

在这里插入图片描述

6 系统关键代码设计

6.1 项目配置

spring:

  datasource:

    url: jdbc:mysql://localhost:3306/springboot_base?serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=utf8

    username: root

    password: 123456

    driver-class-name: com.mysql.cj.jdbc.Driver

    type: com.alibaba.druid.pool.DruidDataSource

    initialSize: 5

    minIdle: 5

    maxActive: 20

    maxWait: 60000

    timeBetweenEvictionRunsMillis: 60000

    minEvictableIdleTimeMillis: 300000

    validationQuery: SELECT 1 FROM DUAL

    testWhileIdle: true

    testOnBorrow: false

    testOnReturn: false

    oolPreparedStatements: true





        #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入

        #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority

        #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j

    filters: stat,wall,log4j

    maxPoolPreparedStatementPerConnectionSize: 20

    useGlobalDataSourceStat: true

    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500



  devtools:

    restart:

      enabled: true

  servlet:

    multipart:

      max-file-size: 3MB



mybatis:

  mapper-locations: classpath:/mapper/*.xml

  type-aliases-package: com.dong.pojo

  configuration:

    map-underscore-to-camel-case: true





photo:

    uploadPhotoPath: D:/钱/pro/second_hand_market-master/springboot_base/src/main/resources/upload/

    #uploadPhotoPath: /home/xiaodong/upload/

    uploadPhotoSuffix: .jpg,.png,.gif,.jpeg

    uploadPhotoMaxSize: 2048



title:

    sysName: 广东理工学院

    homeName: 广东理工二手街

    menuTitle: 菜单列表

    userTitle: 用户列表

    roleTitle: 角色列表

    logTitle: 日志列表

    databaseTitle: 备份列表

    categoryTitle: 分类列表

    goodTitle: 物品列表

    studentTitle: 学生列表

    commentTitle: 评论列表

    newsTitle: 新闻公告列表

6.2 druid数据源配置

@Bean

    public ServletRegistrationBean statViewServlet() {

        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");



        // 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet

        // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到

        Map<String, String> initParams = new HashMap<>();

        initParams.put("loginUsername", "admin"); //后台管理界面的登录账号

        initParams.put("loginPassword", "123456"); //后台管理界面的登录密码



        //后台允许谁可以访问

        //initParams.put("allow", "localhost"):表示只有本机可以访问

        //initParams.put("allow", ""):为空或者为null时,表示允许所有访问

        initParams.put("allow", "");

        //deny:Druid 后台拒绝谁访问

        //initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问



        //设置初始化参数

        bean.setInitParameters(initParams);

        return bean;

    }





    //配置 Druid 监控 之  web 监控的 filter

//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计

    @Bean

    public FilterRegistrationBean webStatFilter() {

        FilterRegistrationBean bean = new FilterRegistrationBean();

        bean.setFilter(new WebStatFilter());



        //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计

        Map<String, String> initParams = new HashMap<>();

        initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");

        bean.setInitParameters(initParams);



        //"/*" 表示过滤所有请求

        bean.setUrlPatterns(Arrays.asList("/*"));

        return bean;

    }

6.3 拦截器

@Override

public void addInterceptors(InterceptorRegistry registry) {

    registry.addInterceptor(homeIndexInterceptor).addPathPatterns("/**").excludePathPatterns(InterceptorConstant.homeGlobalExcludePathPatterns);

    registry.addInterceptor(homeLoginInterceptor).addPathPatterns("/**").excludePathPatterns(InterceptorConstant.homeLoginExcludePathPatterns);

    registry.addInterceptor(adminLoginInterceptor).addPathPatterns("/**").excludePathPatterns(InterceptorConstant.LoginExcludePathPatterns);

    registry.addInterceptor(authorityInterceptor).addPathPatterns("/**").excludePathPatterns(InterceptorConstant.authorityExcludePathPatterns);

}







@Override

public void addViewControllers(ViewControllerRegistry registry) {

    registry.addViewController("system/userinfo").setViewName("admin/system/update_userinfo");

    registry.addViewController("system/login").setViewName("admin/system/login");

    registry.addViewController("system/userPwd").setViewName("admin/system/update_pwd");

    registry.addViewController("system/no_right").setViewName("admin/system/no_right");

    registry.addViewController("home/student/goPublish").setViewName("/home/student/publish");

}

6.4 自定义注解:校验注解

@Target({ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Validata {

     boolean required() default false;//是否检验null



     boolean requiredLength() default false;//是否检验检验长度



     boolean requiredMaxValue() default false;//是否检验最大值



     boolean requiredMinValue() default false;//是否检验最小值



     int maxLength() default -1;//最大长度



     int minLength() default -1;//最小长度



     long maxValue() default -1;//大值



     long minValue() default -1;//最小值



     String errorRequiredMsg() default "";//值为null时的错误提示信息



     String errorMinLengthMsg() default "";//最小长度不满足时的提示信息



     String errorMaxLengthMsg() default "";//最大长度不满足时的提示信息



     String errorMinValueMsg() default "";//最小值不满足时的提示信息



     String errorMaxValueMsg() default "";//最大值不满足时的提示信息

}

6.5 常用工具类

final private char[] code = {

   '2', '3', '4', '5', '6', '7', '8', '9',

   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',

   'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 

   'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',

   'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',

   'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'

};

/**

 * 字体

 */

final private String[] fontNames = new String[]{

      "黑体", "宋体", "Courier", "Arial", 

      "Verdana", "Times", "Tahoma", "Georgia"};

/**

 * 字体样式

 */

final private int[] fontStyles = new int[]{

      Font.BOLD, Font.ITALIC|Font.BOLD

};



/**

 * 验证码长度

 * 默认4个字符

 */

private int vcodeLen = 4;

/**

 * 验证码图片字体大小

 * 默认17

 */

private int fontsize = 21;

/**

 * 验证码图片宽度

 */

private int width = (fontsize+1)*vcodeLen+10;

/**

 * 验证码图片高度

 */

private int height = fontsize+12;

/**

 * 干扰线条数

 * 默认3条

 */

private int disturbline = 3;





public CpachaUtil(){}



/**

 * 指定验证码长度

 * @param vcodeLen 验证码长度

 */

public CpachaUtil(int vcodeLen) {

   this.vcodeLen = vcodeLen;

   this.width = (fontsize+1)*vcodeLen+10;

}



public CpachaUtil(int vcodeLen, int fontSize) {

   this.vcodeLen = vcodeLen;

   this.fontsize = fontSize;

   this.width = (fontsize+1)*vcodeLen+10;

   height = fontsize+12;

}



public CpachaUtil(int vcodeLen, int fontSize, int width, int height) {

   this.vcodeLen = vcodeLen;

   this.fontsize = fontSize;

   this.width = width;

   this.height = height;

}



/**

 * 生成验证码图片

 * @param vcode 要画的验证码

 * @param drawline 是否画干扰线

 * @return

 */

public BufferedImage generatorVCodeImage(String vcode, boolean drawline){

   //创建验证码图片

   BufferedImage vcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

   Graphics g = vcodeImage.getGraphics();

   //填充背景色

   g.setColor(new Color(246, 240, 250));

   g.fillRect(0, 0, width, height);

   if(drawline){

      drawDisturbLine(g);

   }

   //用于生成伪随机数

   Random ran = new Random();

   //在图片上画验证码

   for(int i = 0;i < vcode.length();i++){

      //设置字体

      g.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize));

      //随机生成颜色

      g.setColor(getRandomColor());

      //画验证码

      g.drawString(vcode.charAt(i)+"", i*fontsize+10, fontsize+5);

   }

   //释放此图形的上下文以及它使用的所有系统资源

   g.dispose();

   

   return vcodeImage;

}

/**

 * 获得旋转字体的验证码图片

 * @param vcode

 * @param drawline 是否画干扰线

 * @return

 */

public BufferedImage generatorRotateVCodeImage(String vcode, boolean drawline){

   //创建验证码图片

   BufferedImage rotateVcodeImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

   Graphics2D g2d = rotateVcodeImage.createGraphics();

   //填充背景色

   g2d.setColor(new Color(246, 240, 250));

   g2d.fillRect(0, 0, width, height);

   if(drawline){

      drawDisturbLine(g2d);

   }

   //在图片上画验证码

   for(int i = 0;i < vcode.length();i++){

      BufferedImage rotateImage = getRotateImage(vcode.charAt(i));

      g2d.drawImage(rotateImage, null, (int) (this.height * 0.7) * i, 0);

   }

   g2d.dispose();

   return rotateVcodeImage;

}

/**

 * 生成验证码

 * @return 验证码

 */

public String generatorVCode(){

   int len = code.length;

   Random ran = new Random();

   StringBuffer sb = new StringBuffer();

   for(int i = 0;i < vcodeLen;i++){

      int index = ran.nextInt(len);

      sb.append(code[index]);

   }

   return sb.toString();

}

/**

 * 为验证码图片画一些干扰线

 * @param g 

 */

private void drawDisturbLine(Graphics g){

   Random ran = new Random();

   for(int i = 0;i < disturbline;i++){

      int x1 = ran.nextInt(width);

      int y1 = ran.nextInt(height);

      int x2 = ran.nextInt(width);

      int y2 = ran.nextInt(height);

      g.setColor(getRandomColor());

      //画干扰线

      g.drawLine(x1, y1, x2, y2);

   }

}

/**

 * 获取一张旋转的图片

 * @param c 要画的字符

 * @return

 */

private BufferedImage getRotateImage(char c){

   BufferedImage rotateImage = new BufferedImage(height, height, BufferedImage.TYPE_INT_ARGB);

   Graphics2D g2d = rotateImage.createGraphics();

   //设置透明度为0

   g2d.setColor(new Color(255, 255, 255, 0));

   g2d.fillRect(0, 0, height, height);

   Random ran = new Random();

   g2d.setFont(new Font(fontNames[ran.nextInt(fontNames.length)], fontStyles[ran.nextInt(fontStyles.length)], fontsize));

   g2d.setColor(getRandomColor());

   double theta = getTheta();

   //旋转图片

   g2d.rotate(theta, height/2, height/2);

   g2d.drawString(Character.toString(c), (height-fontsize)/2, fontsize+5);

   g2d.dispose();

   

   return rotateImage;

}

/**

 * @return 返回一个随机颜色

 */

private Color getRandomColor(){

   Random ran = new Random();

   return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220)); 

}

/**

 * @return 角度

 */

private double getTheta(){

   return ((int) (Math.random()*1000) % 2 == 0 ? -1 : 1)*Math.random();

}



/**

 * @return 验证码字符个数

 */

public int getVcodeLen() {

   return vcodeLen;

}

/**

 * 设置验证码字符个数

 * @param vcodeLen

 */

public void setVcodeLen(int vcodeLen) {

   this.width = (fontsize+3)*vcodeLen+10;

   this.vcodeLen = vcodeLen;

}

/**

 * @return 字体大小

 */

public int getFontsize() {

   return fontsize;

}

/**

 * 设置字体大小

 * @param fontsize

 */

public void setFontsize(int fontsize) {

   this.width = (fontsize+3)*vcodeLen+10;

   this.height = fontsize+15;

   this.fontsize = fontsize;

}

/**

 * @return 图片宽度

 */

public int getWidth() {

   return width;

}

/**

 * 设置图片宽度

 * @param width

 */

public void setWidth(int width) {

   this.width = width;

}

/**

 * @return 图片高度

 */

public int getHeight() {

   return height;

}

/**

 * 设置图片高度

 * @param height 

 */

public void setHeight(int height) {

   this.height = height;

}

/**

 * @return 干扰线条数

 */

public int getDisturbline() {

   return disturbline;

}

/**

 * 设置干扰线条数

 * @param disturbline

 */

public void setDisturbline(int disturbline) {

   this.disturbline = disturbline;

}

6.6 菜单工具类

/**

 * 获取所有的顶级菜单类

 * @param menus

 * @return

 */

public static List<Menu> getTopMenus(List<Menu> menus){

   List<Menu> topMenus = new ArrayList<Menu>();

   for(Menu menu : menus){

      if(menu.getParent() == null){

         topMenus.add(menu);

      }

   }

   return topMenus;

}



/**

 * 获取二级菜单分类

 * @param menus

 * @return

 */

public static List<Menu> getSecondMenus(List<Menu> menus){

   List<Menu> secondMenus = new ArrayList<Menu>();

   for(Menu menuParent:menus) {

      for (Menu menu : menus) {

         if (menu.getParent() != null && menu.getParent() == menuParent.getId()&& menuParent.getParent()==null) {

            secondMenus.add(menu);

         }

      }

   }

   return secondMenus;

}



/**

 * 获取三级菜单分类

 * @param menus

 * @return

 */

public static List<Menu> getThirdMenus(List<Menu> menus){

   List<Menu> thirdMenus = new ArrayList<Menu>();

      for (Menu menu : menus) {

         if (menu.getParent() != null && menu.getParent() != 2) {

            thirdMenus.add(menu);

         }

      }



   return thirdMenus;

}



/**

 * 根据菜单url获取菜单id

 * @param url

 * @param menus

 * @return

 */

public static Integer getMenuIdByUrl(String url,List<Menu> menus){

   if(url == null)return null;

   for(Menu menu : menus){

      if(url.equals(menu.getUrl())){

         return menu.getId();

      }

   }

   return null;

}



/**

 * 获取某个菜单id的所有子分类

 * @param parentId

 * @param menus

 * @return

 */

public static List<Menu> getChildren(Integer parentId,List<Menu> menus){

   List<Menu> children = new ArrayList<Menu>();

   if(parentId != null){

      for(Menu menu : menus){

         if(menu.getParent() != null && menu.getParent() == parentId){

            children.add(menu);

         }

      }

   }

   return children;

}



/**

 * 判断给定的url是否存在于指定的列表

 * @param url

 * @param menus

 * @return

 */

public static boolean isExistUrl(String url,List<Menu> menus){

   if(url != null){

      for(Menu menu : menus){

         if(menu.getUrl() != null){

            if(menu.getUrl().contains(url)){

               return true;

            }

         }

      }

   }

   return false;

校验工具类
public static CodeMsg validata(Object object) {

    Field[] fields = object.getClass().getDeclaredFields();

    for (Field field : fields) {

        Validata annotation = field.getAnnotation(Validata.class);

        if (annotation != null) {

            if (annotation.required()) {

                field.setAccessible(true);

                try {

                    Object o = field.get(object);

                    if (StringUtils.isEmpty(o)) {

                        CodeMsg codeMsg = CodeMsg.VALIDATE_ENTITY_ERROR;

                        codeMsg.setMsg(annotation.errorRequiredMsg());

                        return codeMsg;

                    }



                    if (o instanceof String) {

                        if (annotation.requiredLength()) {

                            if (o.toString().length() > annotation.maxLength()) {

                                CodeMsg codeMsg = CodeMsg.VALIDATE_ENTITY_ERROR;

                                codeMsg.setMsg(annotation.errorMaxLengthMsg());

                                return codeMsg;

                            }



                            if (o.toString().length() < annotation.minLength()) {

                                CodeMsg codeMsg = CodeMsg.VALIDATE_ENTITY_ERROR;

                                codeMsg.setMsg(annotation.errorMinLengthMsg());

                                return codeMsg;

                            }

                        }

                    }



                    if(isNumberObject(o)){

                        //判断是否规定检查最小值

                        if(annotation.requiredMinValue()){

                            if(Double.valueOf(o.toString()) <= annotation.minValue()){

                                CodeMsg codeMsg = CodeMsg.VALIDATE_ENTITY_ERROR;

                                codeMsg.setMsg(annotation.errorMinValueMsg());

                                return codeMsg;

                            }

                        }

                        //判断是否规定检查最大值

                        if(annotation.requiredMaxValue()){

                            if(Double.valueOf(o.toString()) > annotation.maxValue()){

                                CodeMsg codeMsg = CodeMsg.VALIDATE_ENTITY_ERROR;

                                codeMsg.setMsg(annotation.errorMaxValueMsg());

                                return codeMsg;

                            }

                        }

                    }



                } catch (Exception e) {

                    e.printStackTrace();

                }





            }

        }



    }

    return CodeMsg.SUCCESS;

}



public static boolean isNumberObject(Object object){

    if(object instanceof Integer)return true;

    if(object instanceof Long)return true;

    if(object instanceof Float)return true;

    if(object instanceof Double)return true;

    return false;

}

6.7 业务代码

/**

    * 系统统一的图片查看方法

    * @param filename

    * @return

    */

   @GetMapping(value="/view")

   public ResponseEntity viewPhoto(@RequestParam(name="filename",required=true)String filename){

      Resource resource = resourceLoader.getResource("file:" + photoConfig.getUploadPhotoPath() + filename);

      try {

         return ResponseEntity.ok(resource);

      } catch (Exception e) {

         return ResponseEntity.notFound().build();

      }

   }



   @PostMapping(value = "upload_photo")

   public Result<String> upload_photo(@RequestParam("photo")MultipartFile photo){

      //获取图片的名称

      String originalFilename= photo.getOriginalFilename();

      //获取图片的后缀

      String suffix=originalFilename.substring(originalFilename.lastIndexOf("."),originalFilename.length());



      //图片格式不正确

      if(!photoConfig.getUploadPhotoSuffix().contains(suffix.toLowerCase())){

         return Result.exception(CodeMsg.UPLOAD_PHOTO_SUFFIX_ERROR);

      }



      if((photo.getSize()/1024)>photoConfig.getUploadPhotoMaxSize()){

         CodeMsg codeMsg=CodeMsg.UPLOAD_PHOTO_ERROR;

         codeMsg.setMsg("图片大小不能大于"+photoConfig.getUploadPhotoMaxSize()+"M");

         return Result.exception(codeMsg);

      }



      File file = new File(photoConfig.getUploadPhotoPath());

      //判断文件夹是否存在

      if(!file.exists()){

         file.mkdir();

      }



      file=new File(photoConfig.getUploadPhotoPath()+ StringUtil.dataFormat(new Date(),"yyyyMMdd" ));

      if(!file.exists()){

         file.mkdir();

      }



      String filename=StringUtil.dataFormat(new Date(),"yyyyMMdd" )+"/"+System.currentTimeMillis()+suffix;

        file=new File(photoConfig.getUploadPhotoPath()+filename);



      try {

         photo.transferTo(file);

      } catch (IOException e) {

         e.printStackTrace();

      }

      logger.info(originalFilename+"图片上传成功");

      return Result.success(filename);

   }

}
@GetMapping(value="/generate_cpacha")

public void generateCpacha(

           @RequestParam(name="vl",defaultValue="4")Integer vcodeLength,//vcodeLength,验证码长度

           @RequestParam(name="fs",defaultValue="21")Integer fontSize,//fontSize,验证码字体大小

           @RequestParam(name="w",defaultValue="98")Integer width,//width,图片宽度

           @RequestParam(name="h",defaultValue="33")Integer height,//height,图片高度

           @RequestParam(name="method",defaultValue="admin_login")String method,//用来调用此方法的名称,以此名称为键,存入到session中

           HttpServletRequest request,

           HttpServletResponse response){

   CpachaUtil cpachaUtil = new CpachaUtil(vcodeLength,fontSize,width,height);

   String generatorVCode = cpachaUtil.generatorVCode();

   //将生成的验证码放入session,以供放后面程序的验证使用

   request.getSession().setAttribute(method, generatorVCode);

   log.info("验证码成功生成,验证码id=" + method + ",验证码为=" + generatorVCode);

   try {

      ImageIO.write(cpachaUtil.generatorRotateVCodeImage(generatorVCode, true), "gif", response.getOutputStream());

   } catch (IOException e) {

      // TODO Auto-generated catch block

      e.printStackTrace();

   }

}

6 最后

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值