MVC的简单项目 客户信息-增删改查 崔希凡JavaWeb 之 day-19
目录
增删改查
以“增”举例
查询
改
查询与修改总结
删除
高级搜索
增删改查
以“增”举例
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相关推荐
- VS2019 C# MySQL 学生信息增删改查(二、改查(续前节))
VS2019 C# MySQL 学生信息增删改查 六.改 1.在FormXiuGai界面中拖入控件,更改相应的属性,如下图所示. 思路:先查找,再将查找到的数据显示在TextBox上,再进行修改.我这 ...
- Spring Boot 学习[四] web项目实战训练(增删改查,分页,排序)
Spring boot非常适合Web应用程序开发.您可以轻松创建自包含的HTTP应用.web服务器采用嵌入式Tomcat,或者Jetty等. 几点说明: Spring boot开发web项目,通常打成 ...
- 使用SpringBoot一小时快速搭建一个简单后台管理(增删改查)(超详细教程)
最近也是临近期末了,各种的期末大作业,后台管理也是很多地方需要用到的,为了方便大家能快速上手,快速搭建一个简单的后台管理,我花了两天时间整理了一下 我会从0开始介绍,从数据库的设计到前端页面的引入最后 ...
- android 增删改查 源码_学生信息增删改查小程序案例(springboot服务端)
项目描述: 该小程序实现了简单的管理员登录,学生信息添加,修改,删除,列表显示等功能,服务器端采用springboot框架提供接口,数据传输格式为json,适合新手学习小程序与服务端的交互,以及增删改 ...
- ASP.NET操作简单的xml,增删改查
温习一下对xml的简单操作,贴出来收藏 xml文件格式: <?xml version="1.0" encoding="utf-8"?> <st ...
- MVC、JSP实现mysql的增删改查功能的封装和简陋的界面交互
1.眼见为实 (1)欢迎界面,总索引:带下划线的三个都是链接 : (2)搜索界面:--有颜色的为链接 (3).点击上面图片中的修改链接之后就会弹出下面的修改界面: (4).修改用户信息的界面 (5). ...
- Asp.net MVC 学习之路-003(增删改查,后端手工,前端生成)
时间:2017-03-09 Asp.net Mvc实现增删改查 1, 创建数据库 可参考我写的EntityFramework实现过程:http://www.jianshu.com/nb/1016674 ...
- Vue 脚手架结合 SpringBoot 构建前后端分离入门项目(实现增删改查)
Vue 脚手架构建前后端分离项目 项目简介与预览 数据库建表 主要模块代码 index.js 路由代码 User.vue 用户组件 RAP2 创建接口进行测试 切换路由组件的显示: this.$rou ...
- Django 学生信息增删改查
Django 小技巧 int(random.uniform(0, 9) * 10000000000) #0-9组成的11位随机数都是唯一的,不会重复 1.Django中的mysql配置 步骤 1.创建 ...
最新文章
- Python 解一道江苏 小升初 数学题,如此变态,看不起来谁?
- 蔚来李斌:自动驾驶好处是解放生产力、保障生命安全
- 前端开发常见问题精选(五)
- Activity动画效果笔记
- java cpu 内存_如何检查Java中的CPU和内存使用情况?
- python汉字作为变量_在Python3x中不能使用汉字作为变量名。()
- 一亿小目标成就_成就卓越的一种方式:自我选择
- Git检出指定的目录-稀疏检出
- php定时任务引入文件,php解决crontab定时任务不能写入文件问题的方法分析
- python入侵网站_入侵服务器简介_python信息安全实战_Python视频-51CTO学院
- 【Axure元件库】彩色圆形图标库 810+个矢量扁平化图标
- 【开发工具集】DLL依赖查看工具——Dependency Walker
- 【牛客网C++服务器项目学习】Day12-网络编程的两种事件处理模式
- simulink的pid参数自整定
- 连接超时与读取超时概述
- 计算机应用文写作C,计算机应用和公文写作
- 【Unity Shader学习笔记】(五)使用鼠标绘制自由多边形(附完整工程源码)
- wx网罗系列之翔实:使用C++开发wxWidgets程序
- 关闭iphone来电mac_如何在Mac和iPhone上关闭通用剪贴板切换(以及为什么要禁用此功能)
- 自定义ViewGroup之仿奥运五环的实现
热门文章
- PhotoShop学习心得分享------(三)通道和图层蒙版
- linux的多用户登录
- 去除面部黑色素小妙招_淡化脸上黑色素方法 几个简单小方法教你轻松白回来...
- 七十二般变化解得了三灾?
- php 5.3 construct_PHP构造方法__construct( )
- Ubuntu 14.04 Nvidia显卡驱动安装及设置
- 卡方检验结果怎么看-医学统计助手★卡方检验,t检验,F检验,秩和检验,方差分析
- 自由浏览播放不了html5,囤货备战剁手节!360安全浏览器“抢货快”三招玩爽双十一...
- 在报酬与体验之间触碰到玩家“G”点才是元宇宙链游发展之道
- C语言 判断是否为闰年 1900不是闰年