JavaWeb基础

1.基本概念

  • 静态web:提供给所有人看的数据是一样的,html,css
  • 动态web:给每个人看的东西不同,servlet/JSP, ASP, PHP

在Java中,动态web资源开发的技术统称为JavaWeb

URL:统一资源定位符(Uniform Resource Locator)每一个有效的URL都指向一个独特的资源比如HTML页面,CSS文档,一幅图像

Tomcat:是一个开源JavaWeb应用服务器,类似的还有Jetty,JBoss。

  • Tomcat实现了Servlet规范,所以也是一个Servlet容器,可以运行我们自己编写的Servlet应用程序处理动态请求。平时用的SpringMVC,Struts2框架就是基于Servlet,所以我们可以在这些框架的基础上进行快速开发,再部署到Tomcat中运行。
  • Tomcat的Connector组件实现了HTTP请求的解析,把解析后的信息交割Servlet处理。
  • Nginx,Apache是目前主流的Web服务器,也可以作为反向代理服务器,他们在处理大量并发的请求连接、连接会话管理和静态内容请求方面比Tomcat有优势。所以一般在实际应用中,先通过Nginx(或Apache)反向代理服务器接受请求,分离动态,静态请求。分别转发给Nginx Web服务器和Tomcat服务器进行处理。

2. Tomcat

2.1 安装Tomcat

下载:Tomcat官网->Tomcat9->Core->64-bit Windows.zip解压

2.2 启动关闭Tomcat

启动:bin/startup.bat,在localhost:8080中访问

关闭:bin/shutdown.bar或者关闭Tomcat窗口

2.3 配置

conf/server.xml可以配置启动的端口号和名称(默认端口号8080)

<Connector port="8080" protocol="HTTP/1.1"
              connectionTimeout="20000"
              redirectPort="8443" />

主机名称(默认主机名称localhost->127.0.0.1) 在C:\Windows\System32\drivers\etc下修改hosts文件将修改的主机名称指向127.0.0.1,浏览器回先检查这个host文件再去DNS服务器解析域名。

<Host name="localhost"  appBase="webapps"
           unpackWARs="true" autoDeploy="true">

3. Maven

maven核心思想:约定大于配置

3.1 安装Maven

下载bin.zip,解压。

在环境变量中添加

  • 变量名:M2_HOME -> 变量值:maven目录下的bin目录
  • 变量名:MAVEN_HOME -> 变量值:maven目录
  • 在系统的PATH中添加:%MAVEN_HONE%\bin

3.2 建立本地仓库

在conf/seetings.xml中settings下添加本地仓库

<localRepository>D:\Environment\apache-maven-3.6.3\maven_repo</localRepository>

3.3 创建maven项目

在IDEA创建项目时选择Maven,选择Create from archetype,选择org.apache.maven.archetypes:maven-archetype-webapp.

在main目录下新建java和resources文件夹,mark as sources root和resources root。最后maven项目结构如下

–src -main -java //源代码 -resources //配置文件 -test -java //测试使用

在maven模板创建的webapp项目中,main目录下,创建java和resources文件夹。右键,将其标记为Sources root和Resources Root

3.4 配置Tomcat

  • 在run/debug configurations中新建Tomcat Server(与TomcatEE Server区分)
  • 选择Application server(在settings->application server中也可以关联tomcat)
  • 下方如果有Warning: No artifacts marked for deployment在Deployment中添加一个artifact(相当于网站总文件夹的名字)

3.5 pom.xml

GAV: groupId, artifactId, version

Packaging: war(JavaWeb打包),jar(java应用打包)

Properties: 项目编码方式和版本

Dependencies: 添加依赖的地方

3.6其他

web.xml中web-app的版本,可以复制粘贴Tomcat的ROOT示例中的xml,那里的web-app是4.0版的。

3.6 Maven中的父子工程

在父项目中,新建module子项目。父项目中的java,子项目都可以用。

在父项目中pom.xml中会有一个

<modules>
   <module>servlet-01</module>
</modules>

4. Servlet

把实现了Servlet接口的Java程序叫做Servlet。为此需要两步:

  • 编写一个类,实现Servlet接口
  • 把开发好的Java类部署到Web服务器中

Sun公司

4.1 静态web

servlet可以实现动态web,静态的html文件可以存放在src->main->webapp下,与index.jsp同级。

部署完成后,在localhost:8008/hello/xxx.html可以访问到该html其中hello是在Tomcat configuration中deployment中的Application context设置。

4.2 HelloServelt

  • 创建java和resources目录后
  • 新建类继承 HttpServlet,重写doGet,doPst。
  • 在web.xml->web-app标签中编写Servlet映射
<servlet>
   <servlet-name>helloPage</servlet-name>
   <servlet-class>com.yuchongt.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>helloPage</servlet-name>
   <url-pattern>/homepage</url-pattern>
</servlet-mapping>
  • 配置tomcat

4.3 ServletContext

类似全局变量,所有servlet共享,可以实现不同servlet之间通信。

//在一个servlet的doGet中
ServletContext servletContext = this.getServletContext();
String username = "tycyt";
servletContext.setAttribute("username", username);
//在另一个servlet的doGet中
getAttribute("username")

ServletContext获取properties

在resources下创建xx.properties,若在java目录下创建,properties有可能不会被打包。

在Servlet中获取properties内容

InputStream resourceAsStream =          this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");

Properties prop= new Properties();
prop.load(resourceAsStream);
String name = prop.getProperty("username");
String pwd = prop.getProperty("password");
PrintWriter writer = resp.getWriter();
writer.println("username: " + name);
writer.println("password: " + pwd);

properties被打包后的地址,在target下查看。

4.4 response下载文件

response下载文件

4.5 response实现验证码

response实现验证码

4.6 response实现重定向

重定向:一个web资源收到客户端请求后,通知客户端去访问另一个web资源。

resp.sendRedirect("/index.jsp");

提交表单重定向:

<!-- 在这之前需要在maven设置servlet-api和servlet-api两个依赖-->
<%@ page language="java" contentType="text/html;utf-8" import="java.util.*" pageEncoding="utf-8"%>
<html>
<body>
<h2>Hello World!</h2>
<!-- action中${}是得到项目根目录,然后再去寻找login作为url的servlet,这样我们点击submit后会重定向到login对应的servlet中-->
<form action="${pageContext.request.contextPath}/login" method="get">
    用户名:<input type="text" name="username">
    密码: <input type="password" name="password">
    <input type="submit">
</form>
</body>
</html>

在login的servlet中可以处理提交内容

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("######## doGet ########");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(username + ":" + password);
        resp.sendRedirect(req.getContextPath() + "/index.jsp");
    }

4.7 request的应用

在上一小节中,使用了req获得web请求的参数。

转发,和重定向不同,转发得到另一个web资源的结果,但是url还是自己的url,没有使用另一个web资源的url。

//注意!与重定向不同。转发不需要在地址前加tomcat中设置的application context,直接写相对地址
req.getRequestDispatcher("/success.jsp").forward(req, resp);

5. Cookie和Session

Cookie是客户端技术,服务器给你的登录凭证

Session是服务器技术,保存用户的会话信息

5.1 Cookie的使用

  • 从请求中获取cookies
  • 服务器响应添加cookies给客户端
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
Cookie[] cookies = req.getCookies();

if (cookies!=null){
    out.write("上次访问的时间是");
    for (Cookie cookie : cookies) {
        if(cookie.getName().equals("lastLoginTime")){
            long lastLoginTime = Long.parseLong(cookie.getValue());
            Date date = new Date(lastLoginTime);
            out.write(date.toString());
        }
    }
}else{
   	//实际有可能自带cookie所以第一次访问不会经过这里
    out.write("这是第一次访问本站");
}

Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
//设置cookie有效期为一天
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);

cookie一般会保存在本地的用户目录下

删除cookie,设置一个同名的cookie将其有效期设置为0,add到resq中,覆盖需要删除的cookie。

如果cookie的内容是中文,又是会遇到乱码问题。使用URLEncoder

URLEncoder.encode("收到", "utf-8")
out.write(URLDecoder.decode(cookie.getValue(), "utf-8"));

5.2 Session(重点)

服务器会给每个用户(浏览器)创建一个Session对象。只要浏览器没有关闭,Session就会一直存在。用户登录后,其他的网页不需要再次登录。

servlet间的通信尽量不用servletContext,而是用Session

在一个servlet中获取session

req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html; charset=utf-8");
HttpSession session = req.getSession();

session.setAttribute("name", URLEncoder.encode("大头", "utf-8"));

String id = session.getId();
boolean aNew = session.isNew();
System.out.println(id + aNew);

在另一个servlet中获取session的信息

req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html; charset=utf-8");
PrintWriter writer = resp.getWriter();

HttpSession session = req.getSession();

String name =  URLDecoder.decode((String) session.getAttribute("name"), "utf-8");
writer.write(name);
System.out.println(name);

设置Session有效时间

<session-config>
    <!--15分钟后session失效-->
    <session-timeout>15</session-timeout>  
</session-config>

删除session同时开启新session

session.invalidate();

Cookie和Session区别

  • Cookie是把用户的数据写给用户的浏览器,可以保存多个
  • Session是把用户的数据写到用户独占的Session中,服务器保存。保存重要信息,减少服务器资源浪费

6. JSP

Java Server Page和Servlet一样,都是用于动态Web技术。

最大特点:写JSP就像在写HTML,不同的是JSP中可以嵌入Java代码,提供动态。

JSP本质上就是一个Servelet。JSP会生成一个class文件,它实现了Servlet。

JSP中的一些内置对象可以在java代码中直接使用

JSP内置对象

6.1 JSPmaven依赖

JSPmaven依赖

6.2 JSP嵌入Java

<!--JSP输出java变量-->
<%= new java.util.Date()%>

<!--JSP输出java语句-->
<% int x = 1; %>

<!--java循环语句中嵌套html语句-->
<% for (int i = 0; i < 5; i++) {%>
<h3>hello world</h3>
<% } %>

<!--JSP声明-->
<%!
    static{
        System.out.println("Loading Servlets");
    }
    private int globalVar = 1;
    public void tyc(){
        System.out.println("Method tyc");
    }
%>

JSP声明会被编译到生成的java类中,其他的会被生成到jspService方法中。

6.3 自定义错误页面

方法一:

写一个jsp页面标注为errorPage

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% page errorPage="error/500.jsp" %>
<html>
<head>
    <title>Welcome to JSP</title>
</head>
<body>
	Error Page    
</body>
</html>

方法二:

在web.xml中添加error-page标签

<error-page>
    <error-code>404</error-code>
	<location>/404.jsp</location>
</error-page>

6.4 JSP中网页组件

写一个header.jsp作为组件,没有html,head,body标签,直接写内容

<h1>
    我是头部
</h1>

在主jsp中,body或者head内添加如下语句

<%@include file="header.jsp"%>
<%-- 或者上面的合二为一,下面的还是独立的页面 --%>
<%-- 上面方法的如果在两个地方都写了int i=1会报错 --%>
<jsp.include  page="common/header.jsp"></jsp.include>

6.5 四大作用域

JSP四大作用域

6.6 JSP使用自建Java类

<!-- 导入自建类-->
<%@ page import="com.yuchognt.pojo.Grade" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Welcome to JSP</title>
</head>
<body>
现在的时间是:<%= new java.util.Date()%><br>
<%
    Grade grade = new Grade();
    grade.setGrade("99");
    grade.setId(45);
    grade.setName("45tyc");
%>
<!-- 上面用Java写的和下面用jspbean写创建对象的效果是一样的-->
<jsp:useBean id="tyc" class="com.yuchognt.pojo.Grade" scope="page" > </jsp:useBean>
<jsp:setProperty name="tyc" property="id" value="44"></jsp:setProperty>
<jsp:setProperty name="tyc" property="name" value="44tyc"></jsp:setProperty>
<jsp:setProperty name="tyc" property="grade" value="99"></jsp:setProperty>

姓名:<jsp:getProperty name="tyc" property="name"/>
id:<jsp:getProperty name="tyc" property="id"/>
成绩:<jsp:getProperty name="tyc" property="grade"/>
<br>
<!-- 上面用Java写的和下面用jspbean写的读取对象内容效果是一样的-->
姓名:<%=grade.getName()%>
id:<%=grade.getId()%>
成绩:<%=grade.getGrade()%>
</body>
</html>

7. MVC三层架构

MVC:Model, View, Controller

MVC三层架构

Model:

  • 业务处理:业务逻辑(Service)
  • 数据持久层:CRUD(Dao)

View:

  • 展示数据
  • 提供链接发起Servlet请求(a, form, img…)

Controller:

  • 接受用户的请求:(req:请求参数,Session信息)
  • 交给业务层处理
  • 控制视图跳转

8. Filter

Filter与Servlet类似,一个Java类implement了Filter接口。

设置文本类型,如果不用filter,需要在每个servlet中修改比编码类型。使用filter可以把需要的servlet设置为utf-8

import javax.servlet.*;
import java.io.IOException;

public class CharacterEncodingFilter implements Filter {

    @Override
    //web 服务器启动的时候初始化了
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //设置字符编码类型为utf-8
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html; charset=utf-8");
        System.out.println("CharacterEncodingFilter执行前");
        filterChain.doFilter(servletRequest, servletResponse);//让请求继续走,如果没有这句,请求到这里就停止了
        System.out.println("CharacterEncodingFilter执行后");
    }

    @Override
    public void destroy() {
        System.out.println("销毁");
    }
}

再web.xml中配置

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>com.yuchongt.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <!--只要是servlet下面的任何请求都会经过这个过滤器-->
    <url-pattern>/servlet/*</url-pattern>
</filter-mapping>

上面过滤器的url配置是意思事root/servlet/下的任意url都会被过滤,所以在需要过滤的servlet的mapping中写符合要求的url,如/servlet/homepage

Java注解和反射

1.注解

注解(annotation)不是程序本身,对程序做出解释,可以被其他程序比如编译器读取。可以附加在package,class,method,field上,通过反射机制对这些元数据访问。

1.1 内置注解

@Override、@Deprecated、@SuppressWarnings最后一个与前两个不同,需要添加参数才能使用,比如@SuppressWarnings(“all”)

1.2 元注解

元注解负责注解其他注解,Java定义了4个元注解

  • @Target:描述注解的使用范围
  • @Retention:需要在什么级别保存(有效),描述注解的生命周期。runtime > class > source
  • @Documented:说明该注解将被包含在javaDoc中
  • @Inherited:子类可以继承父类中的该注解
public class Test{
   @MyAnnotation(name = "tyc")
   public void test(){
  }
}

//这个注解只能用在方法上
@Target(value = {ElementType.METHOD})
@Rentention(RetentionPoilcy.RUNTIME)
@interface MyAnnotaion{
//注解的参数:类型 + 参数名();
   string name() default “”;//如果没有默认值必须赋值
   int id() default -1; //如果默认值为-1,代表不存在
   
}

2. Class类

2.1 动态语言和静态语言

动态语言在运行时可以改变其结构,例如新的函数,对象,甚至引进代码。已有的函数可以被删除或是其他结构上的变化。

主要的动态语言有:C#,JavaScript,PHP,Python

静态语言运行时结构不可变,如Java,C,C++

Java可以利用反射机制获得类似动态语言的特性

2.1 反射与Class类

反射机制允许程序在执行期间借助与Reflection API取得任何类的内部信息,并能直接操作任意对象内部属性及方法。

一个类在内存中只有一个Class对象。类被加载后, 类的整个结构都会被封装在Class对象中。

//tyc是包名,User是包中一个类,可以不是public的那个类
Class c1 = Class.forName("tyc.User");

System.out.println(c1);
System.out.println(c1.toString());

关于Class类:

  • Class对象只能由系统建立
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Class可以完整地得到一个类中所有被加载的结构
  • Class类是Reflection的根源,针对任何想动态加载运行的类,唯有先获得相应的Class对象

2.2 如何获取Class实例

Person st = new Student();
//三种方法获取Class实例
Class c1 = st.getClass();
Class c2 = Class.forName("tyc.Student");
Class c3 = st.getClass();
//获得父类类型
Class c4 = c1.getSuperclass();
System.out.println(c4.toString());

2.3 哪些类型可以有Class 对象

  • class,包括外部类,成员(成员内部类,静态内部类),匿名内部类
  • interface
  • 数组
  • 枚举
  • annotation
  • primitive type
Class c1 = Object.class;        //类
Class c2 = Comparable.class;    //接口
Class c3 = String[].class;      //数组
Class c4 = int[][].class;       //二维数组
Class c5 = Override.class;      //注解
Class c6 = ElementType.class;   //枚举
Class c7 = Integer.class;       //基本类型
Class c8 = void.class;          //空类型

3.类的加载

3.1类加载的过程

  • 加载:将class文件的字节码内容加载到内存中,将这些静态数据转换城方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
  • 链接:将类的二进制代码合并到JVM的运行状态中(检查安全,给静态域分配存储空间,但没有赋值)
  • 初始化:执行类构造器”clinit“方法(执行静态域代码) ,初始化父类

3.2 什么时候发生类的初始化

1、类的主动引用 (一定发生类的初始化)

  • 虚拟机启动时,初始化main方法所在的类
  • new一个类的对象
  • 调用了类的静态成员(除了final常量)和静态方法
  • 使用java.lang.reflect包的方法对类进行反射调用(Class.forname)
  • 初始化一个类,如果父类没有被初始化,先初始化父类

2、类的被动引用(不会发生类的初始化)

  • 通过子类引用父类的静态变量,不会导致子类初始化
  • 通过数组定义类引用
  • 引用常量不会出发此类的初始化(常量在链接阶段 存入了常量池)

3.3 类加载器

  • 引导类加载器:C++编写,负责Java平台的核心库(rt.jar)
  • 扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包
  • 系统类加载器:负责java -classpath或-D java.class.path所指目录下的类与jar包装,最常用的加载器

4. 反射

4.1 获得类的信息

User a = new User();
Class cl = a.getClass();

//获得类名  
System.out.println(c1.getSimpleName());
//获得类的所有属性(包括private)
System.out.println(c1.getDeclaredFields());
//获得类的所有方法(不包含父类的,包括private)
System.out.println(c1.getDeclaredMethods());
//获得指定的构造器
System.out.println(c1.getDeclaredeConstructors());

4.2 动态创建对象和使用其方法

//使用时需要重写toString和抛出一些异常
//通过构造器创建对象
Constructor cs = cl.getDeclaredConstructor(String.class, int.class, int.class);
User u 1 = (User)constructor.newInstance("tyc", 1, 18);
//通过反射使用方法
Method setName = cl.getDeclaredMethods("setName", String.class);
setName.setAccessible(true);//获得private方法操作权限
setName.invoke(u1, "ttt");
//通过反射操作属性
Field name = cl.getDeclaredField("name");
name.setAccessible(true);//获得private字段操作权限
name.set(u1, "tycyt");

4.3 通过反射获取泛型

  • ParameterizedType:表示一种参数化类型,比如Collection<String>
  • GenericArrayType:表示一种元素类型时参数化类型或者类型变量的数组类型
  • TypeVariable:各种类型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式

4.4 通过反射获取注解信息

//自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
   String source();
   int code();
   String act();
}

//使用注解
public class AnnotationClazz {
   @MyAnnotation(source="this is method source",
               code=111,
               act="this is act")
   public void doSth(){}
}

//反射获得注解内容
public class AnnotationUseDemo {
   public static void main(String[] args){
       try {
           Class clazz = Class.forName("AnnotationClazz");
           Method[] methods = clazz.getDeclaredMethods();
           for(Method method:methods){
               MyAnnotation myAnno =             method.getDeclaredAnnotation(MyAnnotation.class);
               if(null != myAnno){ System.out.println("source="+myAnno.source()); System.out.println("code="+myAnno.code());                   System.out.println("act="+myAnno.act());
              }
          }
      } catch (Exception e) {
           e.printStackTrace();
      }
  }
}

IDEA安装leetcode插件

1.添加插件

在File->settings->plugins中搜索leetcode,下载leetcode plugin

2. 登录leetcode

在插件中,输入用户名和密码等信息。点击左侧地球图标登录,返回一个cookie窗口。

在浏览器控制台选择XHR,登录leetcode。选择graphql->headers->Request Headers->cookiez复制到IDEA的cookie窗口,登录即可。

参考资料:

leetcode LoginHelp

JavaScript基础

1. JavaScript框架

1、jQuery:简化了DOM操作,但DOM操作过于频繁,影响前端性能。使用它仅仅是为了兼容IE。

2、Angular:Google收购的前端框架,将后台的MVC模式搬到了前端,并增加了模块化开发的理念,与微软合作,采用TypeScript语法开发。

3、React:Facebook出品,高性能JS前端框架,提出虚拟DOM用于减少真实的DOM操作。在内存中模拟DOM操作,有效提高前端渲染效率。需要学习JSX——一种JS的语法扩展。

4、Vue:渐进式JS框架,综合了Angular模块化和React虚拟DOM的有点。

5、Axios:前端通信框架。Vue不具备通信能力,可以使用Axios,也可以使用jQuery提供的AJAX通信功能。

2.基础内容

2.1 引入JavaScript

<!-- 可以在html中用script标签写js-->
<script>
alert('hello world');
</script>
<!-- 也可以在html中引入单独的js文件-->
<script src = "js/mainPage.js"></script>

2.2 调试js

在浏览器中console调试,console.log(num); 在console打印变量。

在source中可以设置断点,监控变量。

2.3 定义变量及作用域

共有var,let,const三种方式声明变量: 1、var声明的变量作用域为该语句所在的函数内,且变量提升。 2、let声明的变量作用域为该语句所在的代码块内,没有变量提升。 3、const声明的变量不能修改其值。 变量提升,变量的声明被自动提到方法体的顶部,即可以先使用变量再声明。但变量提升不会提升变量的赋值,即如果在最后var x=1;不会报错但在这之前使用x,其为undefine。

嵌套函数中

  • 内部函数可以使用外部函数的成员,反之不行
  • 函数查找变量会由内向外查找,所以内外函数有同名函数变量,各不影响

js实际上只有一个全局作用域windows,任何变量(函数也可以看作变量),假设在函数作用范围内没有找到,就会向外查找,如果在全局作用域也没有找到,则会报错RefrenceError.

因为所有js文件都共用一个window全局作用域,所以不同js文件之间有可能会有变量名的冲突。所以在每一个js文件中,都应该设定一个自己的作用域(全局变量)

let tycApp = {};
tycApp.name = "tyc";

变量名不可以用数字开头,变量名内可以使用$和_

//函数也可以视为变量,第一个alert不会有输出,第二个正常输出。
window.new_alert = window.alert;
window.alert = function(x){
}
alert("111");
alert = new_alert;
alert("222");

2.4 数据类型

1、number:不区分整数小数。科学计数法1.23e3,也可以。还有NaN,Infinity。

2、字符串:’abc’, “qwe”

3、布尔值,逻辑运算与Java一样

4、比较运算符:== 类型不需相同,值相同即返回true。===需要类型和值都相同才能返回true。所以一般不用==,只用===。 NaN===Nan会返回false,NaN与所有数值都不相等,包括自己。只能使用isNaN(NaN)判断一个变量是否是NaN。 与Java类似,不能比较两个小数,存在精度损失问题。比如1/3===1-2/3返回false。只能用Math.abs(1/3===1-2/3)<1e-10.

5、null和undefine:数组越界会返回undefine

6、数组,元素类型不需一致。

let arr = [1, 2, 3, 'hello', null, true];

7、对象:不需要定义类,每个属性间用逗号隔开,最后一个不需要都好

var person = {
   name: "tyc",
   age: 3,
   tags: ['js', 'student', 2020]
}
//取对象的值
person.name

2.5严格检查模式

在代码块或函数开头添加

'use strict'

开启严格检查模式,预防JavaScript的随意性导致的一些问题。

3. 数据类型

3.1 字符串

单引号和双引号包围字符串没有区别,字符串式不可变的。

\'      //转义字符输出'
\n //换行
\t //tab
\u4e2d //Unicode字符
\x41 //ASCII字符

模板字符串:用`包围起来。 可以输出多行字符串,可以方便地插入其他字符串甚至是表达式和函数。

`hello
world
!`
`I am ${name}. I am ${age+3} years old.`

要注意,所有的空格、回车、缩进都会被保留。

3.2 数组

  • 可以直接给arr.length赋值改变数组长度,多出来的部分是undefine,赋值小于原来的长度可以裁切。
  • arr.slice(),类似str.subString() 选取数组的一部分
  • push(), pop()在尾部(右边)入栈出栈 unshift(), shift()在头部(左边)入栈出栈。两种入栈方法都可以一次入多个元素。
  • arr.concat(arr1):返回拼接后的数组,原数组不变。
  • join():用括号内的元素作为连接,拼接数组,返回字符串。
  • for (let i of arr)遍历数组元素,for(let i in arr)遍历下标

3.3 map和set

let map = new Map(['a', 10],['b', 7], ['q', 8]);
map.get('a');
map.set('w',5);
let set = new Set([1,1,2,3,4,1,2]);
set.add(6);
set.has(6);
for (let x of map){}
for (let x of set){}

3.4 对象

  • 对象的所有键都是字符串,键值可以是任意属性。使用一个不存在的属性,返回undefine。
  • delete person.name:可以删除对象的属性 person.hhh = “aaa”:可以直接添加属性
  • ‘age’ in person:判断属性或函数是否在对象中,如果是继承的父类的函数,也会返回true。比如‘toString’ in person返回true
  • person.hasOwnProperty(‘age’):判断一个属性或方法是否是这个对象自身拥有的,继承的会返回flase

3.5 JSON

JSON是一种轻量级的数据交换格式,具有简介清晰的层次结构。

在js中一切皆为对象,任何js支持的类型都可以用JSON来表示,格式:

  • 对象都{}
  • 数组用[]
  • 键值对使用 key : value
let person = {
   name: "tyc",
   age: 5,
   gender: 'male'
}
//JSON字符串和对象的转换
let jsonPerson = JSON.stringify(person);
let qqq = JSON.parse(jsonPerson);

4. 函数

4.1 定义函数

//下面两种写法是一样的
function abs(x){
   if (x<0){
       x = -x
  }
   return x;
}

let abs = function(x){
   if (x<0){
       x = -x
  }
   return x;
}

如果不传递参数给函数,函数会返回NaN 如果没有return,函数会返回undefine

函数的输入参数的个数可以超过定义的数量,只取前面的一部分。

4.2 手动抛出异常

if(typeof x != 'number'){
   throw 'Not a number';
}

4.3 rest

rest参数写在形参的最后面,将输入时,后面的参数合成一个数组,长度不限.

function(a,b, ...rest){
   console.log(rest);
}

4.4 方法

方法就是把函数放在对象里面

//下面两种方法都可以,使用person.age()调用方法
let person = {
   birth: 1996,
   age: function(){
       let now = new Date().getFullYear();
       return now - this.birth;
  }
}

function getAge(){
   let now = new Date().getFullYear();
   return now-this.birth;
}
let person = {
   birth: 1996,
   age: getAge
}

在上面的第二种方法中,getAge()就不能直接调用了。直接调用其中的this实际指向的是window,birth未定义。但可以用apply()指定this是哪一个对象。

//第一个参数是this所代表的对象,第二个数组参数是传递的参数。
getAge.apply(person, []);
# 5. 类

5.1 定义和使用类

class Student{
   constructor(name){
       this.name = name;
  }
   hello(){
       alert('hello');
  }
}
let aa = new Student('aa');

5.2 继承

class GraduateStudent extends Student{
   constructor(name, grade){
       super(name);
       this.grade = grade;
  }
   sayHi(){
       alert('I am a graduate student--'+grade);
  }
}
let ww = new GraduateStudent('tyc', 3)

6. BOM对象

BOM(Browser Object Model)浏览器对象模型。

window:对象代表浏览器窗口(除去浏览器导航等等,显示网页的部分)

Navigator:封装了浏览器的信息,一般不使用,因为可以人为修改

screen:代表屏幕

location:代表当前页面的URL信息

document:当前的页面,HTML,DOM文档树 ,获取cookie

history:前进,后退

7.DOM对象

DOM(Document Object Model)文档对象模型,浏览器网页就是一个DOM树型结构

7.1 获取和更新DOM节点

//在html中有一个div的id是div1
let q = document.getElementById('div1');
q.innerText = '123';
q.innerHTML = '<strong>123</strong>';
q.style.color = 'red';

这是原生代码,之后一般使用jQuery

7.2 删DOM除节点

先获取父节点, 再通过父节点删除自己。删除多个节点时,(兄弟)子节点长度会发生变化,各自的index也会发生变化。

let son = document.getElementById('div1');
let father = som.parentElement;
father.removeChild(son);

7.3 插入节点

//创建新节点,在父节点的子节点的最后添加新节点
//如果时append网页上已有的节点,则会把原来位置的移到新位置
let newNode = document.createElement('p');//创建p标签
newNode.id = 'newN';
newNode.setAttribute('id','newN')//与上面一行作用相同,一般用这个
newNode.innerText = 'new node';
father.append(newNode);
//在中间插入节点
father.insertBefore(oldNode, newNode);

8.表单(验证)

8.1 获取表单内容

let input_text = Document.getElemnetById('username');
input_text.value; //返回输入框的值
let male_radio = Docunment.getElementById('male');
male_radio.value; //返回单多选框的选项内容
male_radio.checked; //返回选项是否被选中

8.2 表单验证

//HTML中设置提交按钮,点击时出发submitCheck函数
<button type='submit' onclick="submitCheck()">提交</button>

//js中,实现submitCheck函数
function submitCheck() {
   let name = document.getElementById('username');
   let pwd = document.getElemnetById('password');
   console.log(name.value);
   console.log(pwd.value);
}

可以给密码加密,设置md5加密。设置一个hidden的文本框,用于接收md5加密后的密码。

9. jQuery

jQuery是一个库,里面有大量js的函数。

9.1导入jQuery

下载jQeury的js文件,放到lib文件夹中。在html的head中导入

<script src="../lib/jquery-3.5.1.js"></script>

9.2 jQuery的选择器

$('p').click();         //标签选择器
$('#id1').click(); //id选择器
$('.class1').click(); //class选择器
$(fucntion (){}); //当页面加载完成后执行内部,内部嵌套其他的jQuery

还有很多种选择器,去看api

9.3 事件

<!-- 设置网页和css -->
<style>
   #dicMove{
       width: 500px;
       height: 500px;
       border: 1px solid red;
  }
</style>
mouse : <span id = 'mouseMove'></span>
<div id="divMove">在这里移动</div>
<!-- jquery -->
<script>
//最外面一层表示等待网页加载完成后执行后面的
$(function () {
$("#divMove").mousemove(function(e){//如果鼠标在divMove移动
       //获取鼠标在页面中的位置,返回给mouseMove的span中
       $('#mouseMove').text('x:'+e.pageX + 'y:'+e.pageY);
  });
})
</script>

参考文档:

jQuery中文API

MySQL基础

1.基本命令

create database database_name [character set utf8 collate utf8_general_ci];     --创建数据库
drop database database_name; --删除数据库
show databases; --查看所有数据库
use database_name; --切换数据库
show tables;   --查看数据库中所有的表
describe table_name; --查看表

2.数据库的列类型

2.1 数值

  • tinyint 1个字节
  • smallint 2个字节
  • mediumint 3个字节
  • int 4个字节
  • bigint 8个字节
  • float 4个字节
  • double 8个字节
  • decimal 字符串形式的浮点数(可用于小数==判断,金融计算)

2.2 字符串

  • char
  • varchar 可变字符串即string
  • tinytext 微型文本
  • text 文本串

2.3 时间日期

  • date YYYY-MM-DD
  • time HH:MM:SS
  • datetime YYYY-MM-DD HH:MM:SS
  • timestamp 1970.1.1到现在的毫秒数utc时间,排除时区干扰
  • year

2.4 null

  • 没有值或者未知
  • 不要参与运算

2.5 数据库的字段属性

  • zerofill: 不足的位数用0填充
  • auto_increment:在上一条的基础上+1,通常用来设计主键index
  • not null:添加数据时该字段不能为null
  • null:添加数据时,若未声明该字段的值,则默认为null
  • length:在int中,显示长度>=length,不足的位数可用zerofill填充。在double,varchar中则表示取值范围

规范化字段,所有表都应当包含下列字段

  • id:主键
  • version:乐观锁
  • is_delete:伪删除
  • gmt_create:创建时间
  • gmt_update:修改时间

3.操作数据库

4.1创建表

create table if not EXISTS `student` (
`id` int(4) not null auto_increment COMMENT'ID',
`name` varchar(30) not null DEFAULT'anonymous' ,
`pwd` varchar(20) not null DEFAULT'12346',
`birthday` datetime default null,
PRIMARY key(`id`)
)ENGINE=INNODB auto_increment=1 DEFAULT CHARSET=utf8;

注意每个表只能有一个auto_increment,而且必须将其设置为primary key。 default后面不用加等号,直接空格写内容。

show create table <table_name>; # 查看表的建立
desc <table_name>; #查看表结构

4.2 修改和删除表

#表操作
alter table <old_name> rename as <new_name>; #修改表名
drop table if exists <table_name>; #删除表
#字段操作
alter table <table_name> add age int(3); #添加字段
alter table <table_name> modify age varchar(10); #修改字段类型
alter table <table_name> change age Age1 int(2); #修改且重命名
alter table <table_name> drop age; #删除字段

4.MySQL数据管理

5.1 添加

insert into <table_name> ('filed1', 'filed2')
values(1_xx, 1_xx), (2_xx, 2_xx);

主键一般自增,可以省略。 可以省略字段,但后面的value需按顺序与表的字段相同。

5.2修改

# 指定修改
update <table_name> set `field1`=xx, `filed2`=xx where id=1 and xx;
#修改所有行
update <table_name> set `field_name`= xx

5.3删除

#删除行
delete from <table_name> where id = 1;#不写where会全删了
#清空表
truncate <table_name>

truncate会重新设置自增列,也不会影响事务。

5.MySQL数据查询

select [all | distinct]
字段列表
from <table_1>
[left| right] inner join <table_2> on XX #联表查询
[where] #指定结果需满足的条件
[group by] #指定结果按照哪几个字段来分组
[having] #过滤分组的记录必须满足的次要条件
[order by] #排序
[limit] #数据检索范围

6.1 基本查询

select version();
select @@auto_increment_increment;#查询自增步长
select `field1`, `field2` from <table_name>; #查询部分列
select distinct `field1` from <table_name>; #去除重复数据

select * from可以查询整张表。

6.2模糊查询

#查询field1中,以qwe开头的数据。
select `field1` from <table_name> 
where `field1` like 'qwe%'; 
#查询field1是12,13,14的数据
select `field1` from <table_name> 
where `field1` in (12, 13, 14); 

在like中,’%’表示任意长度的字符串,’_’表示一个字符。 在in中,上述不能用。

6.3联表查询

# inner join,查询两张表的交集。某(些)字段相同,提取出来合成一行。
# 如果二者没有交集(s.idx永远不等于r.indx),则返回空表。
select s.idx, naem, grade
from student as s
inner join result as r
on s.idx=r.idx;

#left join   和inner的不同在于,会把left表(student)全部行都提取出来,result表中有与之对应的部分,则加上。否则用null描述该行该字段。
# 如果二者没有交集,返回左表。添加在右表中的字段,且值都为null。
select s.idx, naem, grade
from student as s
left join result as r
on s.idx=r.idx
where r.grade>60;

on和where的用法

  • on后面的是连接条件,代表两个表建立关系所遵循的规则
  • where后面的可以看作是筛选条件,是对最终结果集进行过滤所遵循的规则

6.4 分页和排序

# 排序
order by `field1` desc | asc
#数据范围
limit start_idx, length
limit 10,15 #检索11到25

6.5 子查询

例如where中嵌套一个查询

select `name`, `courseNo`, `grade`
from `grade`
where courseNo=(
	select `courseNo` from `course`
    where course_name = 'Mathematics' 
)

需要的东西(Mathematics 这门课的courseNo)在grade这张表里没有。于是利用子查询,先找到courseNo,然后完成条件句courseNo=子查询返回值。

6.6 分组和过滤

# 返回各个科目的平均分和最高分,且只保留平均分大于80的科目
select subjectName, avg(grade), max(grade)
from grade as g
inner join subject as s
on g.subjectNo = s.subjectNo
group by r.subjectNo		#每个subjectNo都有一个平均分和最高分
having avg(grade) > 80;		#此处的过滤只能用having不能用where 

6.7 MySQL函数

字符串函数

select char_length('xxx')
select concat('xx','xxx','xx')
select insert('abcd', pos, len, 'xxx')
select instr('abcdefg', 'ef') #子串在父串中第一次出现位置
select replace('str1', 'str2', 'str3') #把str1中的str2换成str3
# 示例
# 把名字以zhang开头的找出来,并替换成li
select replace(name,'zhang','li') from `student`
where name like`zhang%`;

聚合函数

# 统计表有多少行
select count(* | 1) from <table_name>;   	# 返回所有行
select count(`filed_x`) from <table_name>;	# 会忽略null行
#常用
select avg(grade), max(grade), min(grade) from <table_name>;

6. 事务

ACID原则:

  • 原子性(Atomicity)指事物是一个不可分割的工作单位,要么都发生,要么都不发生。
  • 一致性(Consistency)事务前后,数据的完整性必须保持一致
  • 隔离性(Isolation)多个用户并发访问数据库时,为每个用户开启一个事务,不同事务之间互不干扰。
  • 持久性(Durability)事务一旦被提交,他对数据库中的数据的改变就是永久的。

MySQL默认开启事务自动提交,需先关闭自动提交

set autocommit = 0		#关闭自动提交
start transaction 		#开启事务
update account set money=money-500 where `name`='A'
update account set money=money+500 where `name`='B'
commit					#提交
rollback				#回滚
set autocommit = 1		#开启自动提交

隔离性的问题:

脏读:一个事务读取了另一个没有提交的事务的数据 不可重复读:在同一个事务内重复读取表中的数据,表中数据发生了改变 虚读:在一个事务内,读取了别人插入的数据,导致前后读出来的结果不一致

7.索引

7.1索引的分类

  • 主键索引(primary key):唯一标识,只能有一列作为主键
  • 唯一索引(unique key):一列中的值不能重复
  • 常规索引(key/index)
  • 全文索引(fulltext)

7.2 索引原则

  • 索引不是越多越好
  • 不要对经常变动的数据加索引
  • 索引一般加在查询较多的字段上

8.MySQL备份

可以用Navicat备份,也可以在命令行备份。

# 导出不需要登录MySQL,直接在命令行执行
mysql -hlocalhost -uroot -p123456 <database_name> [<table_name1> <table_name2>] >D:/XX.sql

# 导入需要登录MySQL
source d:/XX.sql

9.规范数据库设计

关系型数据库表设计的三大范式:

  • 数据库的每一列都是不可分割的原子数据。如不能有,学校信息=本科,大四,应分成,学校,年级两个字段。
  • 每张表的字段都和主键(尤其是联合主键)相关,即每张表只描述一件事。
  • 每个字段都应当与主键直接相关,而不能间接相关。

关联查询的不应当超过三张表。有时为了性能,可以忽略三大范式,在表中增加一些冗余字段。

10.JDBC

10.1 第一个JDBC程序

每一个JDBC项目需要添加一个mysql_connector_java jar包到lib中。

首先创建一个lib文件夹,然后将版本对应的jar包复制到lib目录下,最后右键lib文件夹,add as library.

// 第一个jdbc代码
public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法
        //2.用户信息,url中有IP地址和数据库名
        String url = "jdbc:mysql://34.94.222.11:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "1996";
        //3.连接成功 connection代表数据库
        Connection connection =  DriverManager.getConnection(url, username, password);
        //4.执行SQL对象 statement 执行sql的对象
        Statement statement = connection.createStatement();
        //5.执行sql的对象, 可能存在结果,查看返回结果
        String sql = "select * from users";
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
            System.out.println("id=" + resultSet.getObject("id"));
            System.out.println("name=" + resultSet.getObject("NAME"));
            System.out.println("pwd=" + resultSet.getObject("PASSWORD"));
            System.out.println("email=" + resultSet.getObject("email"));
            System.out.println("birthday=" + resultSet.getObject("birthday"));
        }
        //6.释放连接 !!必须做!!
        resultSet.close();
        statement.close();
        connection.close();
}
// statement.executeQuery(); 执行查询操作,返回ResultSet
// statement.execute(); 执行sql
// statement.executeUpdate(); 更新、插入、删除,返回受影响的行数
// resultSet.previous(); 往前移一个
// resultSet.absolute(row); 移动到指定行1
// resultSet.beforeFirst(); 移动到最前面
// resultSet.afterLast(); 移动到最后面

10.2 自建jdbc工具类

将driver, rul, username, password等常量存储到xx.properties中(src文件夹下)。

构建JdbcUtils工具类,静态代码块获取properties内容和加载驱动。构建getConnection和release方法,在具体的application中调用这个类。

// 自建工具类
public class jdbcUtils {
    private  static  String driver = null;
    private  static  String url = null;
    private  static  String username = null;
    private  static  String password = null;
    //驱动只用加载一次,所以写在static中
    static {
        try{
            InputStream in = jdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);

            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driver);

        }catch(IOException | ClassNotFoundException e){
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    //释放连接资源
    public static void release(Connection conn, Statement st, ResultSet res) {
        if(res!=null){
            try {
                res.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        if(st != null){
            try {
                st.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}
//调用工具类
public class TestInsert {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet res = null;
        try {
            conn = jdbcUtils.getConnection();
            st = conn.createStatement();
            String sql = "insert into users(id,`NAME`, `PASSWORD`, `email`, `birthday`)" +
                    "values(5, 'tyc', '123456', '123456@qq.com', '2020-06-06');";
            int i = st.executeUpdate(sql);
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            jdbcUtils.release(conn, st, res);
        }
    }
}

10.3 SQL注入

用户输入sql的语句中添加一些额外的sql语句,比如在password输入’or 1=1 ‘,欺骗服务器。

使用PreparedStatement防止SQL注入,同时提高效率。

public class TestInsert {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet res = null;
        try {
            conn = jdbcUtils.getConnection();
            //使用问号占位符代替输入
            String sql = "insert into users(id,`NAME`, `PASSWORD`, `email`, `birthday`)" +
                    "values(?,?,?,?,?)";
            st = conn.prepareStatement(sql);
            //给参数赋值
            st.setInt(1,6);
            st.setString(2,"qqq");
            st.setString(3,"12345678");
            st.setString(4,"3258@qq,com");
            st.setDate(5, new java.sql.Date(new Date().getTime()));

            int i = st.executeUpdate();

            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            jdbcUtils.release(conn, st, res);
        }
    }
}

10.4 数据库连接池

创建数据库连接是一个很耗时的,也容易对数据库造成安全隐患,所以在程序启动时,建立足够多的连接,由程序动态地对池中的连接进行申请,使用,释放。

常见的数据库连接池有DBCP,Tomcat jdbc Poll.

一般来说,java应用程序访问数据库的过程是:装载驱动程序->通过JDBC建立数据库连接->访问数据库,执行SQL语句->断开数据库连接。

数据库连接池的机制:程序初始化时创建连接池->使用时向连接池申请可用连接->使用完毕,返还连接->程序退出时,断开所有连接,并释放资源。

参考资料: MySQL索引背后的数据结构及算法原理

Navicat远程连接MySQL

1. 端口开放和修改root用户权限

在“Ubuntu服务器安装MySQL”一文中,已完成端口开放和修改root用户IP来源权限。

2. Navicat连接数据库

在localhost填写服务器IP,连接时出现10060 unknown error。原因是服务器未开放端口。在防火墙设置中开放3306端口。

参考资料:
Navicat远程连接MySQL
Navicat远程连接MySQL出现10060 unknow error解决方法

Ubuntu服务器安装MySQL

1.检查系统中是否已安装MySQL

 sudo netstat -tap | grep mysql

若无输出,则未安装MySQL

2.安装MySQL

sudo apt-get install mysql-server mysql-client

中途会要求设置MySQL root用户的密码。

3.修改配置

mysql -uroot -p"password";

登录MySQL,注意-p后面没有空格。

3.1修改端口绑定

sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

bind-address = 127.0.0.1该句注释掉。

3.2 修改访问权限

登录净进入MySQL后输入下面的命令。password需更换,%代表可以从任意的IP访问。

grant all privileges on *.* to root@"%"identified by"password"with grant option;

flush privileges;

4.重启MySQL

sudo service mysql restart

5.删除MySQL

sudo apt-get remove mysql-*

dpkg-l|grep ^rc|awk'{print $2}'|sudo xargs dpkg -P

首先删除MySQL,然后清理残留数据。

CSS基础

1.CSS的三种使用方式

  1. 行内样式:在标签中写style
  2. 内部样式:使用style标签包围css语句
  3. 外部样式:link或import外部css文件(主要用link)
<h1 style="color: red;">
  title_1
</h1>

<style>
   h1{
       color : red;
  }
</style>

<link rel="stylesheet" href="XXX.css">

2.选择器

2.1三种基本选择器

  1. 标签选择器
  2. 类选择器:.class
  3. ID选择器:#id

优先级:id选择器 > class选择器 > 标签选择器

Class和ID的区别

  • 一个class可以包含多个标签,一个ID只能有一个对应的标签
  • 一个标签还可以隶属于多个class,但只能属于一个id
  • 一般来说css用class,js用id

2.2层次选择器

1、后代选择器:某标签所有子标签

body p{
   color: red;
}

2、子选择器:某标签的子一代选择器

body>P{
   color: red;
}

3、相邻选择器:某class(id)的下一个同级标签(不包括自己)

.class + p{
   color: red;
}

4、通用选择器:某class(id)往下的所有同级标签(不包括自己)

.class ~ p{
   color: red;
}

2.3伪类选择器

伪类选择器可以不使用class,选择一个或一些标签。 使用方法:class : xxx

p:nth-of-type(1){
   color: red;   /* 第n个该类型标签*/
ul li:first-child{
   color: red;  
}
a:hover{
   color: red;   /*鼠标悬停时的设置*/
}

2.4属性选择器(常用)

属性选择器选择标签中的具有一定特征的一部分部分 label[attr operator value]

  • [attr]表示带有以 attr 命名的属性的元素。
  • [attr=value]表示带有以 attr 命名的属性,且属性值为 value 的元素。
  • [attr~=value] 表示带有以 attr 命名的属性的元素,并且该属性是一个以空格作为分隔的值列表,其中至少有一个值为 value。
  • [attr|=value]表示带有以 attr 命名的属性的元素,属性值为“value”或是以“value-”为前缀开头。典型的应用场景是用来匹配语言简写代码(如 zh-CN,zh-TW 可以用 zh 作为 value)。
  • [attr^=value]表示带有以 attr 命名的属性,且属性值是以 value 开头的元素。
  • [attr$=value]表示带有以 attr 命名的属性,且属性值是以 value 结尾的元素。
  • [attr*=value]表示带有以 attr 命名的属性,且属性值包含有 value 的元素。
  • [attr operator value i]在属性选择器的右方括号前添加一个用空格隔开的字母 i(或 I),可以在匹配属性值时忽略大小写(支持 ASCII 字符范围之内的字母)。
  • [attr operator value s] 在属性选择器的右方括号前添加一个用空格隔开的字母 s(或 S),可以在匹配属性值时区分大小写(支持 ASCII 字符范围之内的字母)。

3.美化网页

3.1 span和div标签

一般用span标签来组合行内元素(inline element),用div标签来组合块元素(block element),再通过class,id等详细定位。

3.2 文本样式

text-align: center;    /*居中*/
text-indent: 2em;      /*首行缩进 */
height: 10px;
line-height: 10px;     /*height等于line-height可以上下居中*/
vertical-align: middle;/*多个元素上下居中对齐*/
text-decoration: underline; /* 增加下划线*/
text-decoration: none; /*超链接去下划线*/

3.3 列表样式

ul li{
   list-style: none;     /*去掉每列前面的小圆点*/
}

3.4 盒子模型

margin, padding, border 三个为盒子的外边距,内边距和边框

border: 1px solid red; /*粗细,样式,颜色*/
/*比如body初始会有宽度为1的margin,可以在最开始把所有盒子的margin,padding,text-decoration等都取消掉,之后一个个修改*/
margin: 10px 5px;
/* 一个:上下左右 */
/* 两个:上下,左右*/
/* 四个:上,左,下,右 */

3.5 圆角边框

border-radius: 1px 2px 3px 4px;
/* 左上 右上 右下 左下*/
/* 如果四周都等于宽或高的一般,就会成为一个圆形。可以用这个裁剪圆形图像*/

3.6 阴影

box-shadow: 1px 2px 5px red;
/* 右移 下移 模糊半径 颜色*/

4. 浮动

.class{
   display: inline-block; /* 能写在一行的块元素*/
   float: left;/* 元素向左上浮*/
}
/* display还可以是none不显示,inline行元素,block块元素*/

浮动时有可能造成父级边框塌陷,有四种解决方法。

1、增加父级元素的高度。 2、增加一个空的div标签。 3、overflow

overflow: hidden;

4、父类添加一个伪类after(最常用

#father:after{
   content: '';
   display: block;
   clear: both;
}

5. 定位

5.1 相对定位

position: relative;
top: -20px; /* 距离上边-20px,即向上移动20px*/

5.2 绝对定位

相对于父级元素的绝对定位。没有父级元素,则是相对于浏览器定位。 父级元素可以有相对定位,同时绝对定位不会超过父级元素的范围。

5.3固定定位 fixed、

固定定位是相对于窗口的定位,即滑动滚轮不会移动。

5.4 z-index和opacity

z-index表示图层等级,大等级在小的上面。 opacity调整透明度

在Google Cloud Platform上运行Jupyter Notebook

1.服务器的设置

1.1 设置静态IP

在GCP的侧边栏中选择Networking->VPC network->external IP addresses 将外部IP设置为静态IP

1.2 设置防火墙

在侧边栏中选择Networking->VPC network->Firewall rules 开放用于jupyter notebook需要的tcp端口

2.配置Jupyter Notebook

使用GCP的SSH连接服务器

2.1 安装Jupyter Notebook

在终端中输入wget http://repo.continuum.io/archive/Anaconda3-4.0.0-Linux-x86_64.sh 获取 Anaconda 3 的安装文件

输入bash Anaconda3-4.0.0-Linux-x86_64.sh 安装 Anaconda 3。

(可能需要)最后一步输入yes添加jupyter到PATH,或者根据安装后的文字提示在终端内添加路径

安装好之后读取启动文件source ~/.bashrc 以使用 Anaconda 3

2.2 修改配置文件

创建 Jupyter Notebook 的配置文件 jupyter notebook --generate-config

使用Vim或其他编辑器打开该配置文件 vi ~/.jupyter/jupyter_notebook_config.py

在文件最后添加如下设置

c = get_config()
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.port = <Port Number>

端口号需已在防火墙设置中开放

3.启动Jupyter Notebook

在终端中输入 jupyter-notebook --no-browser --port=

在自己的浏览器中输入“服务器的静态IP:端口号”。如1.2.3.4:8888即可