目录

增删改查

以“增”举例

查询

查询与修改总结

删除

高级搜索


增删改查

以“增”举例


Servlet的功能:(MVC中的C,控制层,一般包名servlet或者web)
1)把用户提交到服务器的表单数据,封装(创建)为domain包中的 Customer对象(对应一张数据库表),所以对象是在运行在服务器上的Servlet时创建的(而不是在用户的浏览器的机器上)。(最终传到DAO层中的Customer对象就产生于此时)
2)对用户信息,生成 uuid,因为domain域的实体中有该字段,但没有值。
3)接着把第1)步中得到的Customer对象,作为调用service方法的参数传入。
4)回显到一个页面,提示成功信息。

浏览器:
1)表单数据相关检测。
2)发送增加条目的请求时,URL要带上method对应的方法,从而给servlet用于识别区分,通过这样来调用不同的增删改查Servlet

domain层(实体层,又称POJO),对应于数据库表,它是最底层,也是首先应该写出来的代码。(用excel表的思维去思考更简单)

注意,一个POJO类的对象,是代表对应数据库表中的一行,(每行都有表的结构中的所有列。)

           

DAO层: 这层的类中,应该都持有一个POJO类(domain包中的对应类)的对象作为属性,对于“增”对应的DAO方法void  add(Customer  c),是无返回值void的。

“删”对应DAO方法void  delete(String  cid);

“改”对应DAO方法void   edit(Customer   c); 改的时候,也需要按c.getCid,填到where  cid =  ? ,才能改。

"查"对应DAO方法List<Customer>   findAll(); 这是对应select *  from  t_customer语句,查询出表中所有的行(所有的对象)

下面是“增”的DAO代码。

业务层: (一般包名是service)
add增加业务
1)这里没有复杂的多个操作的业务,直接把servlet传过来的Customer对象,再次直接传递给底层的DAO中的add方法。
持久层 DAO层:持久层是为了增删改查数据库表(MVC中的M,模型层,直接使用JavaBean操作数据库表,一般包名是dao,也可以把domain中的实体也算作M,因为他们是对应的)
调用add方法,把Servlet(控制)层传来的Customer对象,按数据库的对应字段,填入相应的字段。
注意,如果是查询操作,那么是按照sql语句中要查询的字段,利用反射去调用JavaBean中相应的getXXX获取值。

add方法,类比下应该也类似,在DAO层中,使用Servlet封装好的、业务层传下来的Customer对象,去调用对应的getXXX方法得到返回值,作为数据值放入SQL代码中。

业务层代码:
持有一个底层的CustomerDao类引用,将控制层传入自己add方法的参数:Customer类引用,直接传给DAO层的add方法。
把数据(这里是Customer对象)看作水流,这里的业务层Service等于用方法的参数去接收了这个数据,再次将其作为参数放入DAO层方法中。
数据就被直接打入到DAO层的方法中。

servlet层代码(对应MVC中的C,控制层):注意,这里我们使用了继承BaseServlet类

附上BaseServlet代码:
package cn.itcast.web.servlet;import java.io.IOException;
import java.lang.reflect.Method;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public abstract class BaseServlet extends HttpServlet {public void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {/** 1. 获取参数,用来识别用户想请求的方法* 2. 然后判断是否哪一个方法,是哪一个我们就调用哪一个*/String methodName = req.getParameter("method");if(methodName == null || methodName.trim().isEmpty()) {throw new RuntimeException("您没有传递method参数!无法确定您想要调用的方法!");}/** 得到方法名称,是否可通过反射来调用方法?* 1. 得到方法名,通过方法名再得到Method类的对象!*   * 需要得到Class,然后调用它的方法进行查询!得到Method*   * 我们要查询的是当前类的方法,所以我们需要得到当前类的Class*/Class c = this.getClass();   //得到继承自BaseServlet 的  某个Servlet类的class对象。// 注意上面,在Servlet中使用this的用法,将来哪个Servlet对象来跑这段代码,这个this就代表谁!Method method = null;try {
/*下面,通过客户端请求的方法名字符串,得到方法对象 。
原型是下面,从第二个参数开始,是要获取的方法的形参类型。因为仅仅一个方法名,无法唯一的确定下来一个方法,还需要参数。
返回值就不需要了,因为唯一确定一个方法的就是:方法名、形参的(列表),getMethod方法说明:Method  getMethod(String name, Class<?>... parameterTypes)
比如本例中,是要获取一个双参数,第一参数是HttpServletRequest类型,第二参数是HttpServletResponse类型的方法的对象。
实际上就是Servlet层里的add方法,上面有add方法的代码截图。*/method = c.getMethod(methodName,  HttpServletRequest.class,  HttpServletResponse.class);} catch (Exception e) {throw new RuntimeException("您要调用的方法:" + methodName + "(HttpServletRequest,HttpServletResponse),它不存在!");}/** 下面利用反射,调用起method方法对象*/try {String result = (String)method.invoke(this, req, resp); //this是将来跑起来时的Servlet对象,req是将来的请求,resp是将来的响应/** 获取请求处理方法执行后return的字符串,它表示转发或重定向的路径!可以参照上面Servlet层的代码截图* 帮它完成转发或重定向!*//** 如果用户返回的是字符串为null,或为"",那么我们什么也不做!*/if(result == null || result.trim().isEmpty()) {return;}/** 查看返回的字符串中是否包含冒号,如果没有,表示转发* 如果有,使用冒号分割字符串,得到前缀和后缀!* 其中前缀如果是f,表示请求转发;* 如果是r表示重定向* 后缀就是要转发或重定向的路径了!*/if(result.contains(":")) {// 使用冒号分割字符串,得到前缀和后缀int index = result.indexOf(":");//获取冒号的位置String s = result.substring(0, index);//截取出前缀,表示操作String path = result.substring(index+1);//截取出后缀,表示路径if(s.equalsIgnoreCase("r")) {//如果前缀是r,那么重定向!resp.sendRedirect(req.getContextPath() + path);} else if(s.equalsIgnoreCase("f")) {req.getRequestDispatcher(path).forward(req, resp);} else {throw new RuntimeException("你指定的操作:" + s + ",当前版本还不支持!");}} else {//没有冒号,默认为转发!req.getRequestDispatcher(result).forward(req, resp);}} catch (Exception e) {System.out.println("您调用的方法:" + methodName + ", 它内部抛出了异常!");throw new RuntimeException(e);}}
}
CommonUtils类代码,在day14的资料中:
package cn.itcast.commons;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
/*** 小小工具* @author qdmmy6**/
public class CommonUtils {/*** 返回一个不重复的字符串* @return*/public static String uuid() {return UUID.randomUUID().toString().replace("-", "").toUpperCase(); //UUID默认会带横线,替换掉即可,推荐使用UUID}/*** 把map转换成对象* @param map* @param clazz* @return** 把Map转换成指定类型,该map一般来自于 request.getParakmeterMap()方法*/@SuppressWarnings("rawtypes")public static <T> T toBean(Map map, Class<T> clazz) {try {/** 1. 通过参数clazz创建实例* 2. 使用BeanUtils.populate把map的数据封闭到bean中*/T bean = clazz.newInstance();ConvertUtils.register(new DateConverter(), java.util.Date.class);BeanUtils.populate(bean, map);return bean;} catch(Exception e) {throw new RuntimeException(e);}}
}

add.jsp  (对应MVC中的V)

这里要注意的用法,就是输入框的隐藏,就是用来传参数method的,CustomerServlet中有对其的处理。
这是POST提交表单的常见用法。
<input  type = "hidden"   name="method"    value="add">
如果是GET的请求,直接在    /CustomerServlet?method=add

msg.jsp(成功后,跳转到该页面)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'msg.jsp' starting page</title><meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
--></head><body><h1 style="color:green;" align="center">恭喜,${msg }</h1></body>
</html>

domain域  实体代码:

package cn.itcast.cstm.domain;/*** 领域对象 与表单和数据库表在设计上要对应** @author cxf**/
public class Customer {/** 对应数据库表*/private String cid;                // 主键private String cname;            // 客户名称private String gender;                // 客户性别private String birthday;                // 客户生日private String cellphone;                    // 客户手机private String email;                    // 客户邮箱private String description;            // 客户的描述public String getCid() {return cid;}public void setCid(String cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getBirthday() {return birthday;}public void setBirthday(String birthday) {this.birthday = birthday;}public String getCellphone() {return cellphone;}public void setCellphone(String cellphone) {this.cellphone = cellphone;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}@Overridepublic String toString() {return "Customer [cid=" + cid + ", cname=" + cname + ", gender="+ gender + ", birthday=" + birthday + ", cellphone="+ cellphone + ", email=" + email + ", description="+ description + "]";}
}

查询

接下来是查询功能的几个实现模块:
top.jsp      这是主页,用户的输入,即要查询的人,就在这个页面上输入。
list.jsp     这是负责显示查询结果的页面

我们写代码的时候,从底层DAO开始写,之后写 Service层,最后写Servlet层。
但开始运行的时候,调用是最先Servlet;在Servlet中持有Service的对象;   在Service中持有DAO的对象。
查询的逻辑很简单:
1、Servlet上,一步步地利用各层中持有的底层对象,最终利用DAO层中的findAll()方法查到 List<Customer> ,一步步返回到Servlet
2、保存到request域的变量"cstmList"中
3、转发到list.jsp页面,在该页面上显示出request域的变量"cstmList"

DAO层查询模块,下面图是我拼出来的:DAO层需要持有 QueryRuner类的对象

import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.QueryRunner;
import cn.itcast.jdbc.TxQueryRunner;          //  TxQueryRunner extends QueryRunner  自己设计的类
这个SQL语句中没有问号,所以查询方法query中,没有第三参数。

这里的查询方法,在运行时,是不需要Service层 乃至Servlet层传入参数的。如果要接收用户指定信息的查询,还是需要带参数的DAO层查询方法。

Service层代码:  持有DAO层对象,并调用DAO层的方法。(  还有你;一切拜托你)

Servlet层代码:
1、持有Service层对象,并调用Service层方法(还有你;一切拜托你)
2、把得到的查询结果(一个List<Customer>对象),存到request域变量中,以便让jsp负责拿出显示,因为查询的最终目的是让jsp页面进行展示,这点与增加、修改、删除,Servlet层与jsp的交互处理不太一样。

top.jsp中,对应的查询部分,之前搭建时,写的是  <a href="<c:url  value='list.jsp'/>">查询客户</a>
 改为:                              <a href="<c:url  value='/CustomerServlet?method=findAll'/>">查询客户</a>
            以便用户点击后,转入执行    CustomerServlet   中的指定 findAll() 方法。

list.jsp 显示功能代码:    需要注意的是,list.jsp原本被设置为静态的,静态的显示效果好了之后,再往里添加显示域对象
<c:forEach>遍历显示

<c:forEach>标签用于遍历,items是要遍历的request域中对象,var是每次遍历时的对象中元素的赋值变量

list.jsp  完整代码

完整的前端list.jsp代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>客户列表</title><meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
--></head><body>
<h3 align="center">客户列表</h3>
<table border="1" width="70%" align="center">
<tr>
<th>客户姓名</th>
<th>性别</th>
<th>生日</th>
<th>手机</th>
<th>邮箱</th>
<th>描述</th>
<th>操作</th>
</tr>
<c:forEach items="${requestScope.cstmList}" var="cstm">
<tr>
<td>${cstm.cname }</td>
<td>${cstm.gender }</td>
<td>${cstm.birthday }</td>
<td>${cstm.cellphone }</td>
<td>${cstm.email }</td>
<td>${cstm.description }</td>
<td>
<a href="<c:url value='/CustomerServlet?method=preEdit&cid=${cstm.cid }'/>">编辑</a>
<a href="<c:url value='/msg.jsp'/>">删除</a>
</td>
</tr>
</c:forEach>
</table></body>
</html>

编辑用户

编辑用户,需要两次请求过程:
1、在查询结果list.jsp 的基础上,点击要编辑的用户。这是一个request请求。对应的Servlet中处理的方法叫preEidt
     该preEdit方法查询到Customer对象,然后转发到edit.jsp,这是用户真正编辑的界面。

2、第二个过程才是真正编辑的过程,对应Servlet上的方法edit。

关键在第一个过程中,list.jsp怎么带出请求参数cid,这是通过在查询的那次请求request的结果时,就有的  ${cstm.cid} :
所以编辑的动作,要求先有查询。

CustomerServlet 代码:
调用Service层的load方法报错,因为这里是从上层往下层写的。
从list.jsp发来的请求中,抽取 cid 的请求参数值,将这个CID的字符串,往下经过Service层、层层传入DAO层对应的方法中。

这里Servlet层需要 request.setAttribute的原因,是因为要把预处理的查询得到的对象,通过请求转发给编辑页面edit.jsp

____ _________ ______ ________ ______________
CustomerService    中  load方法,一样因为底层没有写。
   该层的load要求传入的String  cid ,来自于Servlet层的传入,  再次调用DAO层方法,把 cid 传入下层DAO层。

___   ___________    ___________   _________________

CustomerDao类,持有TxQueryRunner类的属性;查询方法query中的结果集参数,是单行的BeanHandler;?号只有1处,为cid的值;

上面总体来说,Servlet  的preEdit方法加载到一个结果存在request域中后,将请求request转发到edit.jsp页面;
下面edit.jsp页面要承担显示load方法的加载当前结果到页面的任务;还要承担提供一个“保存、提交、编辑用户”按钮,把用户修改的值传入Servlet的edit方法。

下面就是edit.jsp的代码:

下面65、66两行,为了向/CustomerServlet发送参数 method、cid 
参数method为了指明调用Servlet中的edit方法;       参数cid指明了要修改(编辑)的数据库中的Customer对象。

————————————————————————————————————————————————

Servlet中 编辑 的第二步: edit方法的编写
接受用户请求中的数据,封装为Customer对象,用了CommonUtils类

那么接下来,再继续往下层的edit方法中,层层向下传递Customer对象:

数据库表叫做  t_customer
——————————————————————————————————

BaseServlet

查询与修改总结

如果分析几个Servlet方法中参数的流向:
1、首先,当用户在top.jsp页面输入好了值,点击”查询“按钮后,Servlet中的查询方法findAll() 被调用 ,从数据库中查找到一个Customer的对象存入request域的一个变量名中,再将这个request请求转发 (forward )到list.jsp,去显示出来。
<本过程的Service层中的findAll()方法是无参的,上层Servlet并不向底层DAO传入参数;因为这里要查全部的人员,以List的返回值得到对象的列表>

2、然后,用户可以点击list.jsp上某一个用户对应的"编辑"按钮,该操作会在requst中携带名为cid的参数,同时会调用Servlet中的preEdit方法(本项目中,Servlet中的方法名,不一定与下层的方法名一致!!),进而层层调用下层的load方法,查询到该cid为该值的Customer对象,放在request域的一个变量名中,再将这个请求转发到edit.jsp页面,去显示出来。
<本过程中,被层层传入下层的是一个字符串cid,因为Service层中的load(String  cid)是有参数的,得到的返回值是一个Customer对象类型>

3、再然后,用户填写对该Customer对象准备更新的所有数据,写完后点击 “保存、提交、编辑用户” 按钮,同时会调用Servlet的edit方法,该方法是把最新的Customer对象的值,传入底层的DAO,从而调用QueryRunner类 的update方法完成对数据库的更新,完成编辑功能。
<本过程中,被层层传入下层的是一个Customer对象,因为Service层中的edit(Customer   c)是有参数的 ,编辑(写入)方法返回值类型是void>

所以,查询,是从数据库中查;  编辑,是编辑数据库。
Servlet类中方法的返回值都是String,是为了在执行后,可以把request请求转发到另外的页面,这是自定义的设计。
 
——————————————————————————————————

删除

删除也是建立在查询findAll()的结果集list.jsp之上的。
 在list.jsp上面,每一行查询结果记录右边,不仅有一个编辑按钮,还有一个删除按钮。
在删除按钮上做两个隐藏的输入框,各带一个参数。一个用来指明点击链接后调用的Servlet中的方法delete(String  cid),另一个用来携带cid号。
注意删除的方法名,在Servlet层、Service层、DAO层都是一样的。
Servlet层的方法还是:
1、持有Service类属性对象;调用void  delete(String  cid);
2、设置request域对象的值,在这里就是一个字符串“删除成功!”
3、返回一个字符串,转发到msg.jsp提示成功(msg.jsp中去读取上面设置的域对象);

Service层往下,都是void  delete(String  cid)

_________________________________________________

高级搜索

其实并不麻烦,多条件组合查询而已。
思路:
按照需求,在query.jsp页面上给出可以按何种字段查询的文本框,接收用户的输入。
每一个文本框,都自带一个参数name,在request请求中,传递给Servlet的query方法以备获取;
之后被Servlet获取到,压入调用组合查询的Service层的方法中,层层传递到DAO层的组合查询方法中。
<
Service、DAO层中query方法的参数就是一个Customer对象。对象的有些属性是默认值,非默认值的就是Servlet接收jsp页面的输入,构造而成的Customer对象;
非默认值属性的个数,应该与jsp页面上提供的可接收用户输入的字段个数相同,这是由CommonUtils.toBean()  方法支持的!
CommonUtils.toBean()  可以支持jsp页面上的输入字段,是domain的实体中字段的子集。
>

DAO层需要数据库多表查询的知识。在用户没有对某个字段有查询要求时,应该对该字段不给予where的筛选条件。

DAO层返回值当然与findAll查询一样,是一个List<Customer>数组,因为结果可能不是单行的。

测试时,可能需要造些写测试数据,添加进数据库:

造出300个人

高级搜索流程:

高级搜索的Servlet层:

高级搜索的Service层:

高级搜索的DAO层的query方法:

由于防止用户变更查询业务逻辑,我们使用StringBuiler来处理字符串,先给出一定不变SQL查询字符串的部分:
select  *   from    t_customer    where   1=1
之后往后追加where语句。追加时不需要考虑where会不会被执行,全部都是and了。因为上面的where一定会被执行,这是技巧经验!
<拿一个废条件把where占了,之后就一定都是and了,执行不执行都是and>

因为用户不一定会填写Jsp上的每个查询条件,所以,在DAO里要对jsp页面上有的字段做判断:
如果传过来的Customer对象的指定属性非空(并且不是空串),就要在sql模板上追加一个  “   and   对应属性   like  ? ”

注意,List<Object>   params作为参数列表
qr.query方法的执行,需要 sql模板、结果集、sql模板中的传入值。

最后List<Object>   params作为参数列表的处理中,cname甚至支持查到中间是输入的姓名的记录。其他字段也类似,只有性别是精确的。

如果不想模糊匹配,想精确匹配可以用下面:其他的左匹配、右匹配都是一个意思:

MVC的简单项目 客户信息-增删改查 崔希凡JavaWeb 之 day-19相关推荐

  1. VS2019 C# MySQL 学生信息增删改查(二、改查(续前节))

    VS2019 C# MySQL 学生信息增删改查 六.改 1.在FormXiuGai界面中拖入控件,更改相应的属性,如下图所示. 思路:先查找,再将查找到的数据显示在TextBox上,再进行修改.我这 ...

  2. Spring Boot 学习[四] web项目实战训练(增删改查,分页,排序)

    Spring boot非常适合Web应用程序开发.您可以轻松创建自包含的HTTP应用.web服务器采用嵌入式Tomcat,或者Jetty等. 几点说明: Spring boot开发web项目,通常打成 ...

  3. 使用SpringBoot一小时快速搭建一个简单后台管理(增删改查)(超详细教程)

    最近也是临近期末了,各种的期末大作业,后台管理也是很多地方需要用到的,为了方便大家能快速上手,快速搭建一个简单的后台管理,我花了两天时间整理了一下 我会从0开始介绍,从数据库的设计到前端页面的引入最后 ...

  4. android 增删改查 源码_学生信息增删改查小程序案例(springboot服务端)

    项目描述: 该小程序实现了简单的管理员登录,学生信息添加,修改,删除,列表显示等功能,服务器端采用springboot框架提供接口,数据传输格式为json,适合新手学习小程序与服务端的交互,以及增删改 ...

  5. ASP.NET操作简单的xml,增删改查

    温习一下对xml的简单操作,贴出来收藏 xml文件格式: <?xml version="1.0" encoding="utf-8"?> <st ...

  6. MVC、JSP实现mysql的增删改查功能的封装和简陋的界面交互

    1.眼见为实 (1)欢迎界面,总索引:带下划线的三个都是链接 : (2)搜索界面:--有颜色的为链接 (3).点击上面图片中的修改链接之后就会弹出下面的修改界面: (4).修改用户信息的界面 (5). ...

  7. Asp.net MVC 学习之路-003(增删改查,后端手工,前端生成)

    时间:2017-03-09 Asp.net Mvc实现增删改查 1, 创建数据库 可参考我写的EntityFramework实现过程:http://www.jianshu.com/nb/1016674 ...

  8. Vue 脚手架结合 SpringBoot 构建前后端分离入门项目(实现增删改查)

    Vue 脚手架构建前后端分离项目 项目简介与预览 数据库建表 主要模块代码 index.js 路由代码 User.vue 用户组件 RAP2 创建接口进行测试 切换路由组件的显示: this.$rou ...

  9. Django 学生信息增删改查

    Django 小技巧 int(random.uniform(0, 9) * 10000000000) #0-9组成的11位随机数都是唯一的,不会重复 1.Django中的mysql配置 步骤 1.创建 ...

最新文章

  1. Python 解一道江苏 小升初 数学题,如此变态,看不起来谁?
  2. 蔚来李斌:自动驾驶好处是解放生产力、保障生命安全
  3. 前端开发常见问题精选(五)
  4. Activity动画效果笔记
  5. java cpu 内存_如何检查Java中的CPU和内存使用情况?
  6. python汉字作为变量_在Python3x中不能使用汉字作为变量名。()
  7. 一亿小目标成就_成就卓越的一种方式:自我选择
  8. Git检出指定的目录-稀疏检出
  9. php定时任务引入文件,php解决crontab定时任务不能写入文件问题的方法分析
  10. python入侵网站_入侵服务器简介_python信息安全实战_Python视频-51CTO学院
  11. 【Axure元件库】彩色圆形图标库 810+个矢量扁平化图标
  12. 【开发工具集】DLL依赖查看工具——Dependency Walker
  13. 【牛客网C++服务器项目学习】Day12-网络编程的两种事件处理模式
  14. simulink的pid参数自整定
  15. 连接超时与读取超时概述
  16. 计算机应用文写作C,计算机应用和公文写作
  17. 【Unity Shader学习笔记】(五)使用鼠标绘制自由多边形(附完整工程源码)
  18. wx网罗系列之翔实:使用C++开发wxWidgets程序
  19. 关闭iphone来电mac_如何在Mac和iPhone上关闭通用剪贴板切换(以及为什么要禁用此功能)
  20. 自定义ViewGroup之仿奥运五环的实现

热门文章

  1. PhotoShop学习心得分享------(三)通道和图层蒙版
  2. linux的多用户登录
  3. 去除面部黑色素小妙招_淡化脸上黑色素方法 几个简单小方法教你轻松白回来...
  4. 七十二般变化解得了三灾?
  5. php 5.3 construct_PHP构造方法__construct( )
  6. Ubuntu 14.04 Nvidia显卡驱动安装及设置
  7. 卡方检验结果怎么看-医学统计助手★卡方检验,t检验,F检验,秩和检验,方差分析
  8. 自由浏览播放不了html5,囤货备战剁手节!360安全浏览器“抢货快”三招玩爽双十一...
  9. 在报酬与体验之间触碰到玩家“G”点才是元宇宙链游发展之道
  10. C语言 判断是否为闰年 1900不是闰年