学生选课系统基于javaweb开发

实验目的

在实验中,熟练运用 Java 语言、Web前端技术(HTML、JavaScript、CSS)、Web后端技术(Servlet、JSP、Listener、Filter、JDBC等)、数据库,开发一套基本完善的基于Web的业务系统。通过实验,学生能够掌握Web开发的基本原理、开发方法及开发流程,掌握运用Web基本技术解决实际问题的开发能力。

实验内容

在线课程申请模块功能:

学生登录功能

已有账号学生可以在线登录到申请系统中。

用户账户数据可预先存储到数据库中。

在线申请功能

学生登录后,在可选课程列表中,选择要申请的课程。

每次申请只能选择一门课程,不可重复申请。

申请课程时,应填写必要的申请信息,如:申请原因、上传证明等。

课程详细数据可预先存储到数据库中。

已申请课程,审批进度查询功能

审批过程中的申请可以进行进度查询。

审批状态有:申请已提交、课程主讲教师审批中、课程主管教师审批中、审批成功、申请驳回。

审批结束后,也就是审批状态为成功或者驳回,学生可以点击确认,完成本次申请。

结束本次申请后,在进度查询功能中不能再看到该条申请信息。

被驳回申请的课程,可线下沟通后,再次重新提交新的申请。

已申请课程审批记录查询功能

学生可查询本人已申请的全部记录,包括审批通过和驳回的记录。

申请记录可使用分页显示,可使用多条件查询。

在线审批模块功能:

课程申请审批功能

已有教师角色账号的教师可登录审批功能。

教师角色用户细分为:课程主讲教师和主管教师,主讲教师为该门课程的第一审批人,主管教师为第二审批人。

具体课程的主讲和主管教师对应关系数据,可预先存储到数据库中。

如果已提交的申请不符合申请条件,可以驳回,但驳回必须填写具体的原因,以便学生再次提交新的申请。

已审批申请查询功能

教师可查询已审批的申请,查询结果可使用分页显示,可使用多条件查询。

额外功能:

在系统基本功能(实验内容1、2)基础之上,实现额外功能,使系统功能更加完善。

系统后台

系统用户管理、课申请课程管理、用户审批权限管理(课程与审批教师关系)、审批记录查询、导出已审批通过记录等功能。

创建审批流

可根据具体要求,动态创建课程审批流程,可动态指定不同类别课程的审批步骤及审批人。

拓展需求:

系统设计时需考虑系统的延展性、兼容性、可用性、通用性、健壮性、跨平台及持续集成,不仅能满足现有需要,也要适应未来发展的能力。

适应兼容性,系统应使用持久化层框架(MyBatis)

适应通用性,系统应采用MVC设计模式

适应持续集成,系统应采用容器部署(Docker)

适应可用性,系统界面需布局合理,用户使用方便快捷,用户体验好

适应健壮性,系统应充分考虑运行期间的各种异常情况并加以处理,保证运行时不出现异常或业务逻辑错误等重大问题

实验环境

集成开发工具:IDEA

数据库:MySQL

操作系统:windows10

Web服务器:Tomcat

实验过程与分析

该项目采用MVC架构实现,分为dao层,实体类,filiter过滤器,service层,servelet层,util层

 

该项目的前端由以下几个文件组成

 

如图所示为html登录界面,首先导入css的全面样式,全局样式是指适用于整个网站的样式表,可以在每个页面的header中使用标记将其导入。全局样式可以定义全站通用的字体、颜色、布局等样式,使网站风格统一,提高用户体验。其次导入jQuery,jQuery是一种JavaScript库,旨在简化处理HTML文档、事件处理、动画处理、AJAX等常见任务的编程。可以通过在head中引用jQuery的CDN或本地库来导入jQuery。导入jQuery后可以使用$()或jQuery()语法来选择页面元素、修改样式、绑定事件、发送AJAX请求等。Bootstrap是一种流行的前端开发框架,提供大量的CSS样式和JavaScript组件。通过在head中引用Bootstrap的CDN或本地库,可以使用Bootstrap提供的JavaScript组件,例如导航栏、弹出框、轮播图等,可以使网站开发更加高效,同时提供了一致的UI界面和用户体验。

如图所示为登录界面。

如图所示为arlist部分的代码,这是一个JSP页面,用于展示待处理课程申请信息表。页面中使用了JSTL标签库,并在表格中使用了forEach标签来循环展示ratifylessons对象中的待审批课程申请信息。其中,表格的样式使用了内联样式,并设置了border、margin等属性,使表格具有一定的边框和居中效果。同时,通过使用JSP表达式<%= %>和ServletContext对象中的getAttribute()方法,实现了欢迎用户登录成功的功能,并在页面中展示用户身份和用户名。通过使用if标签和test属性,展示了待处理课程申请的状态,并根据不同的状态设置了状态的显示文字和相关操作按钮,如批准和驳回。

 

用于展示可申请课程信息表。页面中使用了JSTL标签库,并在表格中使用了forEach标签来循环展示lessons对象中的可申请课程信息。其中,表格的样式使用了内联样式,并设置了border、margin等属性,使表格具有一定的边框和居中效果。同时,通过使用JSP表达式<%= %>和ServletContext对象中的getAttribute()方法,实现了欢迎用户登录成功的功能,并在页面中展示用户身份和用户名。通过使用if标签和test属性,展示了可申请课程的状态,并根据不同的状态设置了状态的显示文字和相关操作按钮。

用于展示待处理课程申请信息表。页面中使用了JSTL标签库,并在表格中使用了forEach标签来循环展示ratifylessons对象中的待处理课程申请信息。其中,表格的样式使用了内联样式,并设置了border、margin等属性,使表格具有一定的边框和居中效果。同时,通过使用JSP表达式<%= %>和ServletContext对象中的getAttribute()方法,实现了欢迎用户登录成功的功能,并在页面中展示用户身份和用户名。通过使用if标签和test属性,展示了待处理课程申请的状态,并根据不同的状态设置了状态的显示文字和相关操作按钮,如批准和驳回。

 

如图所示为学生,老师,管理员登录后的界面。

如图所示为实体类,定义Lesson, RatifyLesson, Use类采用get,set方法来定义。

这是一个接口LessonDao,它定义了若干抽象方法,分别用于实现与Lesson相关的数据访问操作,方法包括:

findLessons(String username):根据用户名查找该用户已选课程列表,并返回课程列表的ArrayList。

findByCode(String code):根据课程编号返回对应的课程Lesson对象。

disapprove(String lessoncode,String student,String disapprovereason):驳回指定学生选修的指定课程,并记录驳回的理由(disapprovereason),最终返回操作结果。

insert(Lesson lesson):插入一个新的课程Lesson对象到数据库中,并返回插入操作的结果。

update(Lesson lesson):更新一个已存在的课程对象Lesson,并返回更新操作的结果。

updatestatus(String lessoncode,String student,String status,boolean flag):更新指定学生选修的指定课程的状态,即是否通过,并记录是否通过的标记(flag),最终返回操作结果。

这些方法的具体实现可能在其他类中完成,并实现该接口。

这是一个接口RatifyLessonDao,它定义了若干抽象方法,分别用于实现与RatifyLesson相关的数据访问操作,方法包括:

approve(String code,String student,String lessoncode,String ifratify):批准指定学生选修的指定课程,并记录是否批准(ifratify),最终返回操作结果。

findAll():查询所有申请审核的选课记录列表,并返回列表的ArrayList。

findByTeacher(String teachername):查询指定教师所带课程的所有选课记录列表,并返回列表的ArrayList。

addordelete(RatifyLesson rlesson,String status):根据传入的RatifyLesson对象和状态信息,进行选课申请记录的添加或删除,最终返回操作结果。

disapprove(String lessoncode,String student,String disapprovereason):驳回指定学生选修的指定课程的审核申请,并记录驳回的理由(disapprovereason),最终返回操作结果。

这些方法的具体实现可能在其他类中完成,并实现该接口。

这是一个接口UserDao,主要是用于实现用户数据访问相关的操作,它只有一个抽象方法:

select(String name, String password) :根据用户名和密码,查询对应的用户信息,如果能查询到相应信息,则返回该用户的角色信息(例如管理员、教师、学生等),否则返回空(null)。具体实现需要在其他类中完成,并实现该接口。

如图所示为jdbc连接的配置,driver,url,user,password

这是一个JDBC工具类JDBCUtils,其中包含两个静态方法:

getconnection()方法:用于获取数据库连接对象,利用Java的ResourceBundle类读取属性文件来获取数据库连接的相关信息(驱动、URL、用户名、密码等),并使用JDBC的DriverManager类和Class对象来实现数据库驱动的加载和连接。最终返回连接对象conn。

release()方法:用于释放数据库资源,接受ResultSet、Statement和Connection三个参数,表示需要关闭和释放的数据库相关对象。具体实现是判断每个对象是否为空,如果不为空则调用对应的close()方法来释放资源。

这个工具类通过静态方法的形式封装了数据库连接和释放资源等操作,提供了对外的接口。使用它可以更加便捷地访问数据库并处理数据库资源,提高了代码的可维护性和可读性。

如图所示为该工程的数据库

这是一个过滤器(Filter)类,用于对用户登录状态和请求路径进行拦截和过滤,从而实现访问控制和身份验证的功能。该类实现了Filter接口,主要包含以下方法和功能:

doFilter(ServletRequest request, ServletResponse response, FilterChain chain):实现过滤器的核心方法,用于拦截请求并进行相关处理,该方法接受三个参数:ServletRequest、ServletResponse和FilterChain对象。在该方法的实现中,首先将ServletRequest和ServletResponse对象强制类型转化为HttpServletRequest和HttpServletResponse对象,方便进行相关操作。

对请求路径进行字符串切割处理从而获取路径的具体资源。

接下来,对于特定的请求资源可进行放行,直接调用FilterChain对象的doFilter()方法将请求直接传递给下一个过滤器,或者转发给对应的servlet进行业务逻辑处理。

在对用户身份进行验证时,首先利用HttpServletRequest对象获取Session对象,从Session中获取已保存的用户身份信息,如果身份信息为空,则跳转回登录页面进行用户登录;如果身份信息不为空,则进行请求路径的判断,根据已登录的用户身份信息和请求路径的特定条件,进行请求的放行或转发等操作。

最后通过调用FilterChain对象的doFilter()方法将请求传递给下一个过滤器或servlet进行处理。

该过滤器类的作用主要是对URL的访问进行控制,防止未登录用户进行敏感操作,实现了对用户登录状态和资源访问的管控,可以有效提升系统安全性和稳定性。

这是一个接口LessonService,定义了对课程数据进行操作的一些方法,主要包括如下几个方法: - findLessons(String username):根据用户名查询该用户所选的所有课程信息,返回课程信息的ArrayList集合对象。该方法的实现需要访问数据库,查询对应用户的课程信息。 - findByCode(String code):根据课程代码code查询对应的课程信息,返回一个课程对象。该方法实现也需要访问数据库。 - insert(Lesson lesson):向数据库插入一条课程记录,该记录对应的是一个Lesson对象。具体实现需要将该对象的属性信息插入到对应的数据库表中。 - update(Lesson lesson):更新数据库中的一条课程记录,该记录对应的是一个Lesson对象,具体实现需要将对象的属性信息更新到对应的数据库表中。 - disapprove(String lessoncode,String student,String disapprovereason):将课程上课状态改为未通过,主要针对学生提交的选课申请。

这是一个接口RatifyLessonService,主要是定义了对待审核的选课申请数据进行操作的一些方法,主要包括如下几个方法:

findAll():查询待审核的所有选课申请信息,返回选课申请信息的ArrayList集合对象。该方法的实现需要访问数据库中选课申请表,查询待审核的选课申请信息。

findByTeacher(String teachername):根据教师的用户名查询待审核的选课申请信息,返回教师待审核的选课申请信息的ArrayList集合对象。该方法的实现需要访问数据库中选课申请表,并根据教师名字查询待审核的选课申请信息。

approve(String code,String student,String lessoncode,String ifratify):根据参数中的课程代码、学生用户名、审核结果等信息,对该选课申请进行审核,更新选课申请表中的审核结果。具体实现需要访问数据库中选课申请表,进行相应的更新操作。

void addordelete(RatifyLesson rlesson, String status):根据待审核的选课申请信息和审核状态,对选课申请进行增加或删除操作。具体实现需要访问数据库,并根据审核状态添加或删除选课申请信息。

disapprove(String lessoncode,String student,String disapprovereason):将选课申请的审核状态改为未通过,并填写不通过的原因。具体实现也需要访问数据库,执行相应的更新操作,将该选课申请的审核状态改为未通过,并将不通过的原因填写到对应的字段中。

RatifyLessonService接口的实现主要是针对选课申请的审核和管理。通过该接口的相关方法,可以查询待审核的选课申请,进行选课申请的审核和管理,实现了选课管理的自动化处理。同时,该接口需要访问数据库完成数据操作,确保选课数据的准确性和安全性。

这是一个接口UserService,主要定义了对用户登录的认证操作,包括如下方法:

select(String name, String password):根据用户名和密码进行查询,确定该用户是否合法。如果合法,返回该用户的权限等级;如果不合法,则返回空字符串或抛出异常。该方法主要需要访问数据库进行查询验证,确认用户的合法性。

该接口的实现通常用于验证用户登录时的用户名和密码是否正确,确保只有合法用户才能访问系统。该接口中只定义了一个方法,实现简单,但是对于系统安全性非常重要,能够有效避免未授权用户的访问。在实际应用中,会根据具体需求,扩展该接口的方法和实现,实现更加复杂的用户管理功能

这是一个Servlet类LessonDisapproveServlet,主要实现对学生选课申请不通过的逻辑处理,包括如下方法:

doPost(HttpServletRequest request, HttpServletResponse response):该方法处理学生提交的POST请求,获取学生用户名、课程代码、学生填写的不通过原因、调用LessonService和RatifyLessonService中的disapprove方法,将该选课申请的审核状态改为未通过并填写不通过原因。具体实现需要访问数据库并进行相应的数据库更新操作,确保选课申请的审核状态及不通过原因已更新。处理完成后,重定向到课程审核列表页。

doGet(HttpServletRequest request, HttpServletResponse response):该方法调用doPost方法来处理请求,实现不通过操作。

该Servlet类主要的作用是在学生提交选课申请时,当管理员拒绝该申请时,通过调用LessonService和RatifyLessonService中的disapprove方法,将该选课申请的审核状态改为未通过并填写不通过原因。同时,需要进行数据库操作,将该审核信息保存到数据库中,以便后续审核和查询。该Servlet类的实现主要依赖于LessonService和RatifyLessonService两个服务类的实现,确保选课申请的审核状态及不通过原因的正确更新。

这是一个Servlet类LessonListServlet,主要实现根据用户名查询该用户的所有课程的逻辑处理,包括如下方法: - doPost(HttpServletRequest request, HttpServletResponse response):该方法处理学生提交的POST请求,获取当前登录的用户名、调用LessonService中的findLessons方法,查询该用户的所有课程列表。具体实现需要访问数据库并查询该用户在已选课程表中的信息,以获得该用户的课程列表。查询完成后,将查询结果存入request域中,并转发到list.jsp页面展示课程列表。 - doGet(HttpServletRequest request, HttpServletResponse response):该方法调用doPost方法来处理请求,实现对课程列表的查询操作。该Servlet类主要的作用是在用户提交登录请求后,根据当前登录的用户名查询该用户已选的课程。通过调用LessonService中的findLessons方法和数据库操作,获取该用户的所有课程信息,并将查询结果存入request域中,以便展示在list.jsp页面中。因此,该Servlet类需要与数据库交互,并依赖于LessonService服务类的实现,以获取数据库中的选课数据,并进行相应的查询操作。

这是一个Servlet类LessonUpdateStatusServlet,主要实现对时限内选课申请的审核处理,包括如下方法: - doGet(HttpServletRequest request, HttpServletResponse response):该方法处理管理员提交的GET请求,获取课程代码、审核状态、课程名称、授课教师、学生用户名和随机码,生成RatifyLesson对象,并调用RatifyLessonService中的addordelete方法对该选课申请进行审核操作。审核完成后,根据审核状态使用LessonService中的updatestatus方法对该选课的状态进行更新,确保该课程的选课状态已更新。最后,重定向到课程列表页。 - doPost(HttpServletRequest request, HttpServletResponse response):该方法调用doGet方法来处理请求,实现审核处理操作的逻辑。该Servlet类主要的作用是在管理员登录后,对选课申请进行审核处理。通过调用RatifyLessonService中的addordelete方法生成RatifyLesson对象,传入审核信息,并完成对选课申请的审核操作,同时还需要更新数据库中的选课状态。审核结果将反映在课程的选课状态和审核状态上,以便学生查询自己所选的课程。因此,该Servlet类需要与数据库交互,并需要依赖于LessonService和RatifyLessonService服务类的实现,以实现对数据库的更新操作和审核处理逻辑的实现。

这是一个Servlet类LoginServlet,主要包含用户登录逻辑,包括如下方法: - doPost(HttpServletRequest req, HttpServletResponse resp):该方法处理使用者提交的POST请求,获取登录用的用户名和密码,验证身份信息,并根据身份信息进行页面跳转。具体实现需要调用UserService中的select方法实现对登录信息的查询验证,并将查询结果存入Session中,以便在后续的页面跳转中使用。如果身份信息为学生,则重定向到课程列表页,否则重定向到选课申请列表页。 - doGet(HttpServletRequest req, HttpServletResponse resp):该方法调用doPost方法来处理请求,实现用户登录操作。该Servlet类主要的作用是实现用户登录逻辑,包括用户身份验证、Session存储和页面跳转等操作。通过调用UserService中的select方法,对用户登录信息进行验证,并将用户身份及用户名信息存入Session中,以便在后续操作中使用。同时,根据用户身份信息进行页面的重定向,将用户定向到相应的页面。因此,该Servlet类需要依赖于UserService服务类的实现,并进行Session操作和页面跳转处理。

 

这是一个Servlet类RatifyLessonApproveServlet,主要实现对选课申请的审批处理,包括如下方法: - doGet(HttpServletRequest request, HttpServletResponse response):该方法处理管理员提交的GET请求,获取选课申请的随机码、审批状态、审批结果、学生用户名和课程代码,根据审批结果使用RatifyLessonService中的approve方法对该选课申请进行审批操作,并使用LessonService中的updatestatus方法对选课状态进行更新。最后,将学生用户名和课程代码存入Session中,并重定向到选课申请列表页或管理不通过页面。 - doPost(HttpServletRequest request, HttpServletResponse response):该方法调用doGet方法处理请求,实现审批处理逻辑。 该Servlet类主要的作用是在管理员登录后,对选课申请进行审批处理。通过调用RatifyLessonService中的approve方法,将选课申请的审批结果存入数据库中,并使用LessonService中的updatestatus方法对选课状态进行更新。审批结果将反映在课程的选课状态、审核状态和学生选课名

这是一个Servlet类RatifyLessonListServlet,主要实现选课申请列表的查询处理,包括如下方法: - doPost(HttpServletRequest request, HttpServletResponse response):该方法处理用户提交的POST请求,根据用户身份判断是否是教师用户,如果是教师用户,则使用RatifyLessonService中的findByTeacher方法对选课申请进行查询;如果是学生用户,则使用RatifyLessonService中的findAll方法对选课申请进行查询。查询结果保存在List集合ratifylessons中,并将其存入request域中。最后,根据用户身份转发到相应的选课申请列表页面:教师用户转发到rlist.jsp,学生用户转发到arlist.jsp。 - doGet(HttpServletRequest request, HttpServletResponse response):该方法调用doPost方法处理请求,实现选课申请列表查询处理。该Servlet类主要的作用是实现选课申请列表的查询处理。通过调用RatifyLessonService中的findAll、findByTeacher方法,对选课申请进行查询处理,并将查询结果存入List集合ratifylessons中,并将其存入request域中,以便在选课申请列表页面中进行显示。同时,根据用户身份的

实验创新点

MVC(Model-View-Controller)是一种架构模式,将应用程序分为三个部分,即模型(Model)、视图(View)和控制器(Controller)。MVC架构的优点包括:

分离关注点:MVC模式将应用程序划分为三个部分,每个部分有不同的职责。模型处理数据逻辑,视图处理界面显示,控制器处理用户请求和协调模型和视图之间的交互,使得各个模块之间相互独立,关注点分离,易于维护和修改。

可复用性:MVC模式的各个模块相对独立,模型和视图可以被多个控制器共享,控制器可以根据需要调用多个模型和视图,使得这些模块更容易被复用,并提高了代码的可读性和模块化水平。

易于扩展:MVC模式的各个模块之间不直接依赖,可以通过添加或替换相应的模块来扩展应用程序的功能和灵活性,且不会影响其他的模块。

可测试性:MVC模式的模型、视图和控制器各自独立,这样分离的设计使得组件可以单独测试。这降低了测试复杂度并加速了开发过程。

总之,MVC架构模式在设计应用程序时具有诸多优点,包括分离关注点、可复用性、易于扩展和可测试性,从而提高了应用程序的可维护性和可扩展性,带来更好的用户体验和用户界面。

前端界面中引入bootstrap框架,bootstrap.css是Bootstrap框架中的核心CSS文件,它提供了许多预定义的CSS类和样式,可以通过这些类和样式来展现出具有响应式设计的移动设备友好的网站。

而bootstrap-theme.css是Bootstrap框架中的主题文件,它提供了一些额外的CSS样式来扩展和自定义Bootstrap的外观和感觉。可以用它来修改色彩,布局或字体,从而满足特定的品牌或设计需要。和bootstrap.css一样,bootstrap-theme.css也是可选的,是根据需要进行选择是否使用的。

如图所示为jdbc连接的配置,driver,url,user,password

这是一个JDBC工具类JDBCUtils,其中包含两个静态方法:

getconnection()方法:用于获取数据库连接对象,利用Java的ResourceBundle类读取属性文件来获取数据库连接的相关信息(驱动、URL、用户名、密码等),并使用JDBC的DriverManager类和Class对象来实现数据库驱动的加载和连接。最终返回连接对象conn。

release()方法:用于释放数据库资源,接受ResultSet、Statement和Connection三个参数,表示需要关闭和释放的数据库相关对象。具体实现是判断每个对象是否为空,如果不为空则调用对应的close()方法来释放资源。

 

这个工具类通过静态方法的形式封装了数据库连接和释放资源等操作,提供了对外的接口。使用它可以更加便捷地访问数据库并处理数据库资源,提高了代码的可维护性和可读性。

这是一个过滤器(Filter)类,用于对用户登录状态和请求路径进行拦截和过滤,从而实现访问控制和身份验证的功能。该类实现了Filter接口,主要包含以下方法和功能:

doFilter(ServletRequest request, ServletResponse response, FilterChain chain):实现过滤器的核心方法,用于拦截请求并进行相关处理,该方法接受三个参数:ServletRequest、ServletResponse和FilterChain对象。在该方法的实现中,首先将ServletRequest和ServletResponse对象强制类型转化为HttpServletRequest和HttpServletResponse对象,方便进行相关操作。

对请求路径进行字符串切割处理从而获取路径的具体资源。

接下来,对于特定的请求资源可进行放行,直接调用FilterChain对象的doFilter()方法将请求直接传递给下一个过滤器,或者转发给对应的servlet进行业务逻辑处理。

在对用户身份进行验证时,首先利用HttpServletRequest对象获取Session对象,从Session中获取已保存的用户身份信息,如果身份信息为空,则跳转回登录页面进行用户登录;如果身份信息不为空,则进行请求路径的判断,根据已登录的用户身份信息和请求路径的特定条件,进行请求的放行或转发等操作。

最后通过调用FilterChain对象的doFilter()方法将请求传递给下一个过滤器或servlet进行处理。

该过滤器类的作用主要是对URL的访问进行控制,防止未登录用户进行敏感操作,实现了对用户登录状态和资源访问的管控,可以有效提升系统安全性和稳定性。

 

实验总结

该项目使用 Java 语言、Web前端技术(HTML、JavaScript、CSS)、Web后端技术(Servlet、JSP、Listener、Filter、JDBC等)、数据库,开发了一套基本完善的基于Web的业务系统。通过这个项目,我对web开发的知识有了更一步的了解,在开发一个web项目前选择合适的架构模式是设计一个应用程序的重要因素之一,MVC架构模式可以使应用程序的功能清晰分割,有利于代码的管理和维护。在开发过程中,要尽可能地模块化,将代码分解成小而独立的模块,便于单独测试和维护,同时使得代码更加可读,易于他人维护和阅读。在这个项目中,不同的功能模块被分解成不同的实体类、数据访问对象、服务、控制器、视图等模块,使得代码逻辑更加清晰。在测试过程中,遇到bug,可以在程序中添加断点,方便程序运行,从而更清楚地了解问题所在。通过这次实验,我的知识得到了深化。

 

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值