首页
壁纸
留言板
友链
更多
统计归档
Search
1
TensorBoard:训练日志及网络结构可视化工具
12,579 阅读
2
主板开机跳线接线图【F_PANEL接线图】
6,840 阅读
3
Linux使用V2Ray 原生客户端
6,009 阅读
4
移动光猫获取超级密码&开启公网ipv6
4,356 阅读
5
NVIDIA 显卡限制功率
3,088 阅读
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
登录
/
注册
Search
标签搜索
好物分享
学习笔记
linux
MySQL
nvidia
typero
内网穿透
webdav
vps
java
cudann
gcc
cuda
树莓派
CNN
图像去雾
ssh安全
nps
暗通道先验
阿里云
jupiter
累计撰写
354
篇文章
累计收到
69
条评论
首页
栏目
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
页面
壁纸
留言板
友链
统计归档
搜索到
7
篇与
的结果
2022-04-18
javaWeb学习笔记
1、基本概念1.1、前言web开发:web,网页的意思,www.baidu.com·静态webhtml,css提供给所有人看的数据始终不会发生变化!动态web淘宝,几乎是所有的网站;提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同!技术栈:Servlet/JSP,ASP,PHP1.2、web应用程序web应用程序:可以提供浏览器访问的程序;a.html、b.html.….多个web资源,这些web资源可以被外界访问,对外界提供服务;你们能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。URL这个统一的web资源会被放在同一个文件夹下,web应用程序>Tomcat:服务器一个web应用由多部分组成(静态web,动态web)html,css,jsjsp,servletJava程序jar包配置文件(Properties)Web酸用程序编写完毕后,若想提供给外界访问;需费一个服务蔬来统一管理1.3、静态web*.htm, *.html这些都是网页的后缀、如果服务器上一直存在这些东西,我们就可以直接进行读取、需要网络;静态web存在的缺点Web页面无法动态更新,所有用户看到都是同一个页面轮播图,点击特效:伪动态JavaScript[实际开发中,它用的最多]VBScript它无法和数据库交互(数据无法持久化,用户无法交互)1.4、 动态web页面会动态展示,“web页面的展示效果因人而异” 缺点:假如服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布(停机维护);优点:Web页面可以动态更新,所有用户看到都不是同一个页面它可以与数据库交互(数据持久化:注册,商品信息,用户信息………) 2、web服务器2.1、技术讲解ASP:微软:国内最早流行的就是ASP;·在HTML中嵌入了VB的脚本,ASP+COM;·在ASP开发中,基本一个页面都有几干行的业务代码,页面极其换乱·维护成本高!C#IISphp:PHP开发速度很快,功能很强大,跨平台,代码很简单(70%,WP)无法承载大访问量的情况(局限性)jSP/Servlet: B/S;浏览和服务器C/S:客户端和服务器sun公司主推的B/S架构基于Java语言的(所有的大公司,或者一些开源的组件,都是用Java写的)可以承载三高问题带来的影响;语法像ASP,ASP->JSP,加强市场强度;2.2、web服务器服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息; lIS 微软的;ASP.,Windows中自带的 Tomcat 面向百度编程: Tomcat是Apache 软件基金会(Apache Software Foundation)的jakarta项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat中得到体现,因为Tomcat 技术先进、性能稳定,而且免费,因而深受lava爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。Tomcat 服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。对于一个Java初学web的人来说,它是最佳的选择Tomcat 实际上运行JSP页面和Serlet。Tornct最新版易9.0工作3-5年之后,可以尝试手写Tomcat服务器;下载tomcat:安装or解压了解配置文件及目录结构这个东西的作用3、Tomcat3.1安装tomcat tomcat官网:http://tomcat.apache.org/ 3.2、Tomcat启动和配置文件夹作用: 访问测试:http://localhost:8080/ 可能遇到的问题:Java环境变量没有配置闪退问题:需要配置兼容性乱码问题:配置文件中设置可以修改 conf/logging.properties 中的 java.util.logging.ConsoleHandler.encoding = GBK 解决乱码问题3.3、配置可以配置启动的端口号tomcat的默认端口号为:8080mysql:3306http:80https:443<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />可以配置主机的名称默认的主机名为:localhost->127.0.0.1默认网站应用存放的位置为:webapps <Host name="www.qinjiang.com" appBase="webapps" unpackWARs="true" autoDeploy="true">**高难度面试题: 请你谈谈网站是如何进行访问的!**输入一个域名;回车检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射;有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问 127.0.0.1 www.qinjiang.com没有:去DNS服务器找,找到的话就返回,找不到就返回找不到; 4.可以配置一下环境变量(可选性)3.4、发布一个web网站不会就先模仿将自己写的网站,放到服务器(Tomcat)中指定的web应用的文件夹(webapps)下,就可以访问了网站应该有的结构--webapps :Tomcat服务器的web目录 -ROOT -kuangstudy :网站的目录名 - WEB-INF -classes : java程序 -lib:web应用所依赖的jar包 -web.xml :网站配置文件 - index.html 默认的首页 - static -css -style.css -js -img -.....HTTP协议:面试 Maven:构建工具Maven安装包Servlet入门HelloWorld!Servlet配置 ·原理4、Http4.1、什么是HTTPHTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。文本:html,字符串,…超文本:图片,音乐,视频,定位,地图.……端口:80Https:安全的端口:4434.2、两个时代http1.0HTTP/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接http2.0HTTP/1.1:客户端可以与web服务器连接后,可以获得多个web资源。4.3、Http请求客户端–发请求(Request)–服务器百度:Request URL:https://www.baidu.com/ 请求地址 Request Method:GET get方法/post方法 Status Code:200 OK 状态码:200 Remote(远程) Address:14.215.177.39:443 Accept:text/html Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.9 语言 Cache-Control:max-age=0 Connection:keep-alive1、请求行请求行中的请求方式:GET请求方式:Get,Post,HEAD,DELETE,PUT,TRACT.…get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。2、消息头Accept:告诉浏览器,它所支持的数据类型 Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1 Accept-Language:告诉浏览器,它的语言环境 Cache-Control:缓存控制 Connection:告诉浏览器,请求完成是断开还是保持连接 HOST:主机..../.4.4、Http响应服务器–响应…….客户端百度:Cache-Control:private 缓存控制 Connection:Keep-Alive 连接 Content-Encoding:gzip 编码 Content-Type:text/html 类型 1、响应体Accept:告诉浏览器,它所支持的数据类型 Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1 Accept-Language:告诉浏览器,它的语言环境 Cache-Control:缓存控制 Connection:告诉浏览器,请求完成是断开还是保持连接 HOST:主机..../. Refresh:告诉客户端,多久刷新一次; Location:让网页重新定位;2、响应状态码200:请求响应成功200 3xx:请求重定向重定向:你重新到我给你新位置去;4xx:找不到资源404:资源不存在;5xx:服务器错误500:服务器代码错误502:网关错误常见面试题: 当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?5、Maven我为什么要学习这个技术?在Javaweb开发中,需要使用大量的jar包,我们手动去导入;如何能够让一个东西自动帮我导入和配置这个jar包。由此,Maven诞生了!5.1 Maven项目架构管理工具我们目前用来就是方便导入jar包的! Maven的核心思想:约定大于配置有约束,不要去违反。Maven会规定好你该如何去编写我们Java代码,必须要按照这个规范来;5.2下载安装Maven官网:https://maven.apache.org/ 下载完成后,解压即可; 小狂神友情建议:电脑上的所有环境都放在一个文件夹下,方便管理;5.3配置环境变量在我们的系统环境变量中配置如下配置:M2\_HOME maven目录下的bin目录MAVEN\_HOME maven的目录在系统的path中配置%MAVEN\_HOME%\bin 测试Maven是否安装成功,保证必须配置完毕!5.4阿里云镜像镜像:mirrors作用:加速我们的下载国内建议使用阿里云的镜像<mirror> <id>nexus-aliyun</id> <mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>D:Enmvironment\apache-maven-3.6.2conf\settings.xml (狂神老师配置源和仓库的文件位置)5.5本地仓库在本地的仓库,远程仓库; 建立一个本地仓库:localRepository<localRepository>D:\Environment\apache-maven-3.6.2\maven-repo</localRepository>5.6 ~ 5.13笔记-下载地址下载地址:https://lanzoui.com/ibuibxi本站缓存后面的 5.6 ~ 5.13 + 案例演示 (图)**后面第 5 剩下部分的笔记建议配合狂神的 “javaweb-06:IDEA中Maven的操作”、“javaweb-07:解决大家遇到的一些问题” 仔细(回)看**6、Servlet6.1、Servlet简介Servlet就是sun公司开发动态web的一门技术Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:编写一个类,实现Serlet接口把开发好java类部署到web服务器中。把实现了Servlet接口的Java程序叫做,ServletSerlvet接口Sun公司有两个默认的实现类:HttpServlet,GenericServled6.2、HelloServlet构建一个普通的Maven项目,等理面的sc目录,以后我们的学习就在这个项目里面建立Moudel;这个空的工程就题Maven主工程;关于Maven父子工程的理解; 父项目中会有 <modules> <module>servlet-01</module> </modules>子项目会有 <parent> <artifactId>javaweb-02-servlet</artifactId> <groupId>com.kuang</groupId> <version>1.0-SNAPSHOT</version> </parent>父项目中的java子项目可以直接使用son extends fatherMaven环境优化修改web.xml为最新的<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> </web-app>将maven的结构搭建完整编写一个Servlet程序编写一个普通类实现Servlet接口,这里我们直接继承HttpServlet public class HelloServlet extends HttpServlet { //由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //ServletOutputStream outputStream = resp.getOutputStream(); PrintWriter writer = resp.getWriter(); //响应流 writer.print("Hello,Serlvet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } 编写Servlet的映射 为什么需要映射:我们写的是JAVA程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需 要再web服务中注册我们写的Servlet,还需给他一个浏览器能够访问的路径; <!--注册Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.kuang.servlet.HelloServlet</servlet-class> </servlet> <!--Servlet的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>配置Tomcat 注意:配置项目发布的路径就可以了 启动测试,OK! 6.3、Servlet原理Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会: 6.4、Mapping问题一个Servlet可以指定一个映射路径 <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>一个servlet可以指定多个映射路径 <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello3</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello4</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello5</url-pattern> </servlet-mapping> 一个servlet可以指定通用映射路径 <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>默认请求路径 <!--默认请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>指定一些后缀或者前缀等等… <!--可以自定义后缀实现请求映射 注意点,*前面不能加项目映射的路径 hello/sajdlkajda.qinjiang --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.qinjiang</url-pattern> </servlet-mapping>优先级问题 指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求; <!--404--> <servlet> <servlet-name>error</servlet-name> <servlet-class>com.kuang.servlet.ErrorServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>error</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> 6.5、ServletContextweb容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;1、共享数据我在这个Servlet中保存的数据,可以在另外一个servlet中拿到;public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //this.getInitParameter() 初始化参数 //this.getServletConfig() Servlet配置 //this.getServletContext() Servlet上下文 ServletContext context = this.getServletContext(); String username = "秦疆"; //数据 context.setAttribute("username",username); //将一个数据保存在了ServletContext中,名字为:username 。值 username } } public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); String username = (String) context.getAttribute("username"); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); resp.getWriter().print("名字"+username); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.kuang.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet> <servlet-name>getc</servlet-name> <servlet-class>com.kuang.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping>测试访问结果;2、获取初始化参数 <!--配置一些web应用初始化参数--> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/mybatis</param-value> </context-param>protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); String url = context.getInitParameter("url"); resp.getWriter().print(url); }3、请求转发@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); System.out.println("进入了ServletDemo04"); //RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); //转发的请求路径 //requestDispatcher.forward(req,resp); //调用forward实现请求转发; context.getRequestDispatcher("/gp").forward(req,resp); } 4、读取资源文件 Properties在java目录下新建properties在resources目录下新建properties发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath: 思路:需要一个文件流username=root12312 password=zxczxczxcpublic class ServletDemo05 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/kuang/servlet/aa.properties"); Properties prop = new Properties(); prop.load(is); String user = prop.getProperty("username"); String pwd = prop.getProperty("password"); resp.getWriter().print(user+":"+pwd); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } 访问测试即可ok;6.6、HttpServletResponseweb服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest 对象,代表响应的一个HttpServletResponse;如果要获取客户端请求过来的参数:找HttpServletRequest如果要给客户端响应一些信息:找HttpServletResponse1、简单分类负责向浏览器发送数据的方法 servletOutputstream getOutputstream() throws IOException; Printwriter getwriter() throws IOException;负责向浏览器发送响应头的方法void setCharacterEncoding(String var1); void setContentLength(int var1); void setContentLengthLong(long var1); void setContentType(String var1); void setDateHeader(String varl,long var2) void addDateHeader(String var1,long var2) void setHeader(String var1,String var2); void addHeader(String var1,String var2); void setIntHeader(String var1,int var2); void addIntHeader(String varl,int var2);响应的状态码 2、下载文件向浏览器输出消息(一直在讲,就不说了)下载文件要获取下载文件的路径下载的文件名是啥?设置想办法让浏览器能够支持下载我们需要的东西获取下载文件的输入流创建缓冲区获取OutputStream对象将FileOutputStream流写入到bufer缓冲区使用OutputStream将缓冲区中的数据输出到客户端! @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1.待下载文件的路径和文件名 String filePath = "C:\\Users\\itrb\\Desktop\\数据标注\\res.jpg"; String fileName = filePath.substring(filePath.lastIndexOf("\\") + 1); // 2.设置让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则有可能乱码 resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")); // 3.获取待下载文件的输入流 FileInputStream fileInputStream = new FileInputStream(filePath); //4.创建缓冲区 int len = 0; byte[] buffer = new byte[1024]; // 5.获取输出流 OutputStream out = resp.getOutputStream(); // 6.往输出流写入文件 while ((len=fileInputStream.read(buffer))>0){ out.write(buffer); } // 7.关闭流 fileInputStream.close(); out.close(); }3、验证码功能验证怎么来的?前端实现后端实现,需要用到Java的图片类,生产一个图片package top.inat.servlet; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; public class ImageServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //让浏览器3秒自动刷新一次; resp.setHeader("refresh","3"); //在内存中创建一个图片 BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB); //得到图片 Graphics2D g = (Graphics2D) image.getGraphics(); //笔 //设置图片的背景颜色 g.setColor(Color.white); g.fillRect(0,0,80,20); //给图片写数据 g.setColor(Color.BLUE); g.setFont(new Font(null,Font.BOLD,20)); g.drawString(makeNum(),0,20); //告诉浏览器,这个请求用图片的方式打开 resp.setContentType("image/jpeg"); //网站存在缓存,不让浏览器缓存 resp.setDateHeader("expires",-1); resp.setHeader("Cache-Control","no-cache"); resp.setHeader("Pragma","no-cache"); //把图片写给浏览器 ImageIO.write(image,"jpg", resp.getOutputStream()); } //生成随机数 private String makeNum(){ Random random = new Random(); String num = random.nextInt(9999999) + ""; StringBuffer sb = new StringBuffer(); for (int i = 0; i < 7-num.length() ; i++) { sb.append("0"); } num = sb.toString() + num; return num; } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }<servlet> <servlet-name>image</servlet-name> <servlet-class>top.inat.servlet.ImageServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>image</servlet-name> <url-pattern>/image</url-pattern> </servlet-mapping> 常见场景:用户登录 void sendRedirect(String var1) throws IOException;测试:@override protected void doGet(HttpservletRequest req, HttpservletResponse resp) throws ServletException, IOException { resp. sendRedirect("/r/img");//重定向 /* resp. setHeader("Location","/r/img"); resp. setstatus (302); */ } index.jsp<html> <head> <meta charset="GBK"> <title>Login Test</title> </head> <body> <h2>Hello World!</h2> <%--这里提交交的路径,需要寻找到项目的路径--%> <%--${pageContext.request.contextPath}代表当前的项目--%> <form action="${pageContext.request.contextPath}/login" method="get"> username: <input type="text" name="username"> <br> password: <input type="password" name="password"> <br> <input type="submit"> </form> </body> </html>RequestTest.javapackage top.inat.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //处理方求 String username = req.getParameter("username"); String password = req.getParameter("password"); System.out.println(username + ":" + password); resp.sendRedirect("/success.jsp"); } }重定向页面success.jsp<%@ page contentType="text/html; charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>success</h1> </body> </html>web.xml配置<servlet> <servlet-name>login</servlet-name> <servlet-class>top.inat.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping>导入依赖的jar包<dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> <scope>provided</scope> </dependency> </dependencies>6.7、HttpServletRequestHttpServletRequest代表客户端的请求,用户通过Http协议访问服务器, HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息; 获取参数,请求转发 自己创建类,且需要继承HttpServlet类@Override protected void doGet(HttpservletRequest req. HttpservletResponse resp) throws ServletException, IOException { req. setcharacterEncoding("utf-8"); resp.setcharacterEncoding("utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); String[] hobbys = req.getParameterValues("hobbys"); System.out.println("=========="); //后台接收中文乱码问题 System. out.println(username); System. out.println(password); System. out.println(Arrays.tostring(hobbys)); System. out.println("============"); system. out.println(req.getContextPath()); //通过请求转发 //这里的/代表当前的web应用 req.getRequestDispatcher("/success.jsp").forward(req,resp); }7、Cookie、Session7.1、会话会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话;有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过,称之为有状态会话;你能怎么证明你是西开的学生?发票 西开给你发票学校登记 西开标记你来过了一个网站,怎么证明你来过?客户端 服务端服务端给客户端一个 信件,客户端下次访问服务端带上信件就可以了; cookie服务器登记你来过了,下次你来的时候我来匹配你; seesion7.2、保存会话的两种技术cookie客户端技术 (响应,请求)session服务器技术,利用这个技术,可以保存用户的会话信息? 我们可以把信息或者数据放在Session中!常见常见:网站登录之后,你下次不用再登录了,第二次访问直接就上去了!7.3、Cookie从请求中拿到cookie信息服务器响应给客户端cookieCookie[] cookies = req.getCookies(); //获得Cookie cookie.getName(); //获得cookie中的key cookie.getValue(); //获得cookie中的vlaue new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie cookie.setMaxAge(24*60*60); //设置cookie的有效期 resp.addCookie(cookie); //响应给客户端一个cookiecookie:一般会保存在本地的 用户目录下 appdata;一个网站cookie是否存在上限!聊聊细节问题一个Cookie只能保存一个信息;一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;Cookie大小有限制4kb;300个cookie浏览器上限删除Cookie;不设置有效期,关闭浏览器,自动失效;设置有效期时间为 0 ;编码解码:URLEncoder.encode("秦疆","utf-8") URLDecoder.decode(cookie.getValue(),"UTF-8")7.4、Session(重点) 什么是Session:服务器会给每一个用户(浏览器)创建一个Seesion对象;一个Seesion独占一个浏览器,只要浏览器没有关闭,这个Session就存在;用户登录之后,整个网站它都可以访问!–> 保存用户的信息;保存购物车的信息……Session和cookie的区别:Cookie是把用户的数据写给用户的浏览器,浏览器保存 (可以保存多个)Session把用户的数据写到用户独占Session中,服务器端保存 (保存重要的信息,减少服务器资源的浪费)Session对象由服务创建;使用场景:保存一个登录用户的信息;购物车信息;在整个网站中经常会使用的数据,我们将它保存在Session中;设置Session:package top.inat.servlet; import top.inat.pojo.Person; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class SetSession extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //解决乱码问题 req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=utf-8"); //得到Session HttpSession session = req.getSession(); //给Session中存东西 session.setAttribute("user",new Person("秦疆",1)); //获取Session的ID String sessionId = session.getId(); resp.getWriter().write("session创建成功,ID:"+sessionId); //Session创建的时候做了什么事情; //Cookie cookie = new Cookie("JSESSIONID",sessionId); //resp.addCookie(cookie); } }获取Session:package top.inat.servlet; import top.inat.pojo.Person; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.net.URLEncoder; public class GetSession extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //得到Session HttpSession session = req.getSession(); Object sessionData = session.getAttribute("user"); if(sessionData!=null){ Person person = (Person)sessionData; System.out.println(person.toString()); resp.setCharacterEncoding("UTF-8"); resp.getWriter().write("session is : "+person.toString()); }else { resp.setCharacterEncoding("UTF-8"); resp.getWriter().write("session is : null"); } } }注销Session:HttpSession session = req.getSession(); session.removeAttribute("user"); //手动注销Session session.invalidate();会话自动过期:web.xml配置<!--设置Session默认的失效时间--> <session-config> <!--15分钟后Session自动失效,以分钟为单位--> <session-timeout>15</session-timeout> </session-config>8、JSP8.1、什么是JSPJava Server Pages : Java服务器端页面,也和Servlet一样,用于动态Web技术!最大的特点:写JSP就像在写HTML区别:HTML只给用户提供静态的数据JSP页面中可以嵌入JAVA代码,为用户提供动态数据;8.2、JSP原理思路:JSP到底怎么执行的!代码层面没有任何问题服务器内部工作tomcat中有一个work目录;IDEA中使用Tomcat的会在IDEA的tomcat中生产一个work目录我电脑的地址:C:\Users\Administrator.IntelliJIdea2018.1\system\tomcat\Unnamed\_javaweb-session-cookie\work\Catalina\localhost\ROOT\org\apache\jsp发现页面转变成了Java程序! 浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!JSP最终也会被转换成为一个Java类!JSP 本质上就是一个Servlet//初始化 public void _jspInit() {} //销毁 public void _jspDestroy() {} //JSPService public void _jspService(.HttpServletRequest request,HttpServletResponse response){}判断请求内置一些对象final javax.servlet.jsp.PageContext pageContext; //页面上下文 javax.servlet.http.HttpSession session = null; //session final javax.servlet.ServletContext application; //applicationContext final javax.servlet.ServletConfig config; //config javax.servlet.jsp.JspWriter out = null; //out final java.lang.Object page = this; //page:当前 HttpServletRequest request //请求 HttpServletResponse response //响应输出页面前增加的代码response.setContentType("text/html"); //设置响应的页面类型 pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;以上的这些个对象我们可以在JSP页面中直接使用!在JSP页面中;只要是 JAVA代码就会原封不动的输出;如果是HTML代码,就会被转换为:out.write("<html>\r\n");这样的格式,输出到前端!8.3、JSP基础语法任何语言都有自己的语法,JAVA中有,。 JSP 作为java技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),Java所有语法都支持!JSP表达式 <%--JSP表达式 作用:用来将程序的输出,输出到客户端 <%= 变量或者表达式%> --%> <%= new java.util.Date()%>jsp脚本片段<%--jsp脚本片段--%> <% int sum = 0; for (int i = 1; i <=100 ; i++) { sum+=i; } out.println("<h1>Sum="+sum+"</h1>"); %>脚本片段的再实现 <% int x = 10; out.println(x); %> <p>这是一个JSP文档</p> <% int y = 2; out.println(y); %> <hr> <%--在代码嵌入HTML元素--%> <% for (int i = 0; i < 5; i++) { %> <h1>Hello,World <%=i%> </h1> <% } %>JSP声明 <%! static { System.out.println("Loading Servlet!"); } private int globalVar = 0; public void kuang(){ System.out.println("进入了方法Kuang!"); } %>JSP声明:会被编译到JSP生成Java的类中!其他的,就会被生成到\_jspService方法中!在JSP,嵌入Java代码即可!<%%> <%=%> <%!%> <%--注释--%>JSP的注释,不会在客户端显示,HTML就会!8.4、JSP指令<%@page args.... %> // 定制错误页面等 <%@include file=""%> <%--@include会将两个页面合二为一--%> <%@include file="common/header.jsp"%> <h1>网页主体</h1> <%@include file="common/footer.jsp"%> <hr> <%--jSP标签 jsp:include:拼接页面,本质还是三个 --%> <jsp:include page="/common/header.jsp"/> <h1>网页主体</h1> <jsp:include page="/common/footer.jsp"/>8.5、9大内置对象PageContext 存东西Request 存东西ResponseSession 存东西Application 【SerlvetContext】 存东西config 【SerlvetConfig】outpage ,不用了解exceptionpageContext.setAttribute("name1","秦疆1号"); //保存的数据只在一个页面中有效 request.setAttribute("name2","秦疆2号"); //保存的数据只在一次请求中有效,请求转发会携带这个数据 session.setAttribute("name3","秦疆3号"); //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器 application.setAttribute("name4","秦疆4号"); //保存的数据只在服务器中有效,从打开服务器到关闭服务器request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;8.6、JSP标签、JSTL标签、EL表达式<!-- JSTL表达式的依赖 --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> </dependency> <!-- standard标签库 --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency>EL表达式: ${ }获取数据执行运算获取web开发的常用对象JSP标签<%--jsp:include--%> <%-- http://localhost:8080/jsptag.jsp?name=kuangshen&age=12 --%> <jsp:forward page="/jsptag2.jsp"> <jsp:param name="name" value="kuangshen"></jsp:param> <jsp:param name="age" value="12"></jsp:param> </jsp:forward>JSTL表达式JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和Java代码一样!格式化标签SQL标签XML 标签核心标签 (掌握部分)JSTL标签库使用步骤引入对应的 taglib使用其中的方法在Tomcat 也需要引入 jstl的包,否则会报错:JSTL解析错误c:if<head> <title>Title</title> </head> <body> <h4>if测试</h4> <hr> <form action="coreif.jsp" method="get"> <%-- EL表达式获取表单中的数据 ${param.参数名} --%> <input type="text" name="username" value="${param.username}"> <input type="submit" value="登录"> </form> <%--判断如果提交的用户名是管理员,则登录成功--%> <c:if test="${param.username=='admin'}" var="isAdmin"> <c:out value="管理员欢迎您!"/> </c:if> <%--自闭合标签--%> <c:out value="${isAdmin}"/> </body>c:choose c:when<body> <%--定义一个变量score,值为85--%> <c:set var="score" value="55"/> <c:choose> <c:when test="${score>=90}"> 你的成绩为优秀 </c:when> <c:when test="${score>=80}"> 你的成绩为一般 </c:when> <c:when test="${score>=70}"> 你的成绩为良好 </c:when> <c:when test="${score<=60}"> 你的成绩为不及格 </c:when> </c:choose> </body>c:forEach<% ArrayList<String> people = new ArrayList<>(); people.add(0,"张三"); people.add(1,"李四"); people.add(2,"王五"); people.add(3,"赵六"); people.add(4,"田六"); request.setAttribute("list",people); %> <%-- var , 每一次遍历出来的变量 items, 要遍历的对象 begin, 哪里开始 end, 到哪里 step, 步长 --%> <c:forEach var="people" items="${list}"> <c:out value="${people}"/> <br> </c:forEach> <hr> <c:forEach var="people" items="${list}" begin="1" end="3" step="1" > <c:out value="${people}"/> <br> </c:forEach> 9、JavaBean实体类JavaBean有特定的写法:必须要有一个无参构造属性必须私有化必须有对应的get/set方法;一般用来和数据库的字段做映射 ORM;ORM :对象关系映射表—>类字段–>属性行记录---->对象people表idnameageaddress1秦疆1号3西安2秦疆2号18西安3秦疆3号100西安class People{ private int id; private String name; private int id; private String address; } class A{ new People(1,"秦疆1号",3,"西安"); new People(2,"秦疆2号",3,"西安"); new People(3,"秦疆3号",3,"西安"); }过滤器文件上传邮件发送JDBC 复习 : 如何使用JDBC , JDBC crud, jdbc 事务10、MVC三层架构什么是MVC: Model view Controller 模型、视图、控制器10.1、以前的架构用户直接访问控制层,控制层就可以直接操作数据库;servlet--CRUD-->数据库 弊端:程序十分臃肿,不利于维护 servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码 架构:没有什么是加一层解决不了的! 程序猿调用 ↑ JDBC (实现该接口) ↑ Mysql Oracle SqlServer ....(不同厂商)10.2、MVC三层架构![[(img-BWDJGUCN-1588757845419)(JavaWeb.assets/1568424227281.png)]](/usr/uploads/auto_save_image/9592f95019658738dc15d361abdf4563.png)Model业务处理 :业务逻辑(Service)数据持久层:CRUD (Dao - 数据持久化对象)View展示数据提供链接发起Servlet请求 (a,form,img…)Controller (Servlet)接收用户的请求 :(req:请求参数、Session信息….)交给业务层处理对应的代码控制视图的跳转登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)---->交给业务层处理登录业务(判断用户名密码是否正确:事务)--->Dao层查询用户名和密码是否正确-->数据库11、Filter (重点)比如 Shiro安全框架技术就是用Filter来实现的Filter:过滤器 ,用来过滤网站的数据;处理中文乱码登录验证….(比如用来过滤网上骂人的话,我***我自己 0-0) Filter开发步骤:导包编写过滤器导包不要错 (注意)![[(img-HHsC3JBD-1588757845420)(JavaWeb.assets/1568425162525.png)]](/usr/uploads/auto_save_image/d77950ebea39793fce0f02c34f7dd8d5.png)实现Filter接口,重写对应的方法即可 public class CharacterEncodingFilter implements Filter { //初始化:web服务器启动,就以及初始化了,随时等待过滤对象出现! public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter初始化"); } //Chain : 链 /* 1. 过滤中的所有代码,在过滤特定请求的时候都会执行 2. 必须要让过滤器继续同行 chain.doFilter(request,response); */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=UTF-8"); System.out.println("CharacterEncodingFilter执行前...."); chain.doFilter(request,response); //让我们的请求继续走,如果不写,程序到这里就被拦截停止! System.out.println("CharacterEncodingFilter执行后...."); } //销毁:web服务器关闭的时候,过滤器会销毁 public void destroy() { System.out.println("CharacterEncodingFilter销毁"); } } 在web.xml中配置 Filter <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.kuang.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <!--只要是 /servlet的任何请求,会经过这个过滤器--> <url-pattern>/servlet/*</url-pattern> <!--<url-pattern>/*</url-pattern>--> <!-- 别偷懒写个 /* --> </filter-mapping>12、监听器实现一个监听器的接口;(有n种监听器)编写一个监听器实现监听器的接口…依赖的jar包//统计网站在线人数 : 统计session public class OnlineCountListener implements HttpSessionListener { //创建session监听: 看你的一举一动 //一旦创建Session就会触发一次这个事件! public void sessionCreated(HttpSessionEvent se) { ServletContext ctx = se.getSession().getServletContext(); System.out.println(se.getSession().getId()); Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); if (onlineCount==null){ onlineCount = new Integer(1); }else { int count = onlineCount.intValue(); onlineCount = new Integer(count+1); } ctx.setAttribute("OnlineCount",onlineCount); } //销毁session监听 //一旦销毁Session就会触发一次这个事件! public void sessionDestroyed(HttpSessionEvent se) { ServletContext ctx = se.getSession().getServletContext(); Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); if (onlineCount==null){ onlineCount = new Integer(0); }else { int count = onlineCount.intValue(); onlineCount = new Integer(count-1); } ctx.setAttribute("OnlineCount",onlineCount); } /* Session销毁: 1. 手动销毁 getSession().invalidate(); 2. 自动销毁 */ } web.xml中注册监听器<!--注册监听器--> <listener> <listener-class>com.kuang.listener.OnlineCountListener</listener-class> </listener>看情况是否使用!13、过滤器、监听器常见应用监听器:GUI编程中经常使用;public class TestPanel { public static void main(String[] args) { Frame frame = new Frame("中秋节快乐"); //新建一个窗体 Panel panel = new Panel(null); //面板 frame.setLayout(null); //设置窗体的布局 frame.setBounds(300,300,500,500); frame.setBackground(new Color(0,0,255)); //设置背景颜色 panel.setBounds(50,50,300,300); panel.setBackground(new Color(0,255,0)); //设置背景颜色 frame.add(panel); frame.setVisible(true); //监听事件,监听关闭事件 frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { super.windowClosing(e); } }); } }用户登录之后才能进入主页!用户注销后就不能进入主页了!用户登录之后,向Sesison中放入用户的数据进入主页的时候要判断用户是否已经登录;要求:在过滤器中实现!HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; if (request.getSession().getAttribute(Constant.USER_SESSION)==null){ response.sendRedirect("/error.jsp"); } chain.doFilter(request,response);14、JDBC什么是JDBC : Java连接数据库!![[(img-rZzTXmtn-1588757845422)(JavaWeb.assets/1568439601825.png)]](/usr/uploads/auto_save_image/db8ad90b34dbe3b84a5f730e5148e3ab.png)需要jar包的支持:java.sqljavax.sqlmysql-conneter-java… 连接驱动(必须要导入)实验环境搭建 CREATE TABLE users( id INT PRIMARY KEY, `name` VARCHAR(40), `password` VARCHAR(40), email VARCHAR(60), birthday DATE ); INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(1,'张三','123456','zs@qq.com','2000-01-01'); INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(2,'李四','123456','ls@qq.com','2000-01-01'); INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(3,'王五','123456','ww@qq.com','2000-01-01'); SELECT* FROM users; 导入数据库依赖<!--mysql的驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>IDEA中连接数据库:![[(img-XErw4ElS-1588757845423)(JavaWeb.assets/1568440926845.png)]](/usr/uploads/auto_save_image/c0a6ec2b544b455988beeb40af2afae8.png)JDBC 固定步骤:加载驱动连接数据库,代表数据库向数据库发送SQL的对象Statement : CRUD编写SQL (根据业务,不同的SQL)执行SQL关闭连接(先开的后关)public class TestJdbc { public static void main(String[] args) throws ClassNotFoundException, SQLException { //配置信息 //useUnicode=true&characterEncoding=utf-8 解决中文乱码 String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; //1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); //2.连接数据库,代表数据库 Connection connection = DriverManager.getConnection(url, username, password); //3.向数据库发送SQL的对象Statement,PreparedStatement : CRUD Statement statement = connection.createStatement(); //4.编写SQL String sql = "select * from users"; //5.执行查询SQL,返回一个 ResultSet : 结果集 ResultSet rs = statement.executeQuery(sql); while (rs.next()){ System.out.println("id="+rs.getObject("id")); System.out.println("name="+rs.getObject("name")); System.out.println("password="+rs.getObject("password")); System.out.println("email="+rs.getObject("email")); System.out.println("birthday="+rs.getObject("birthday")); } //6.关闭连接,释放资源(一定要做) 先开后关 rs.close(); statement.close(); connection.close(); } } 预编译SQLpublic class TestJDBC2 { public static void main(String[] args) throws Exception { //配置信息 //useUnicode=true&characterEncoding=utf-8 解决中文乱码 String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; //1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); //2.连接数据库,代表数据库 Connection connection = DriverManager.getConnection(url, username, password); //3.编写SQL String sql = "insert into users(id, name, password, email, birthday) values (?,?,?,?,?);"; //4.预编译 PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1,2);//给第一个占位符? 的值赋值为1; preparedStatement.setString(2,"狂神说Java");//给第二个占位符? 的值赋值为狂神说Java; preparedStatement.setString(3,"123456");//给第三个占位符? 的值赋值为123456; preparedStatement.setString(4,"24736743@qq.com");//给第四个占位符? 的值赋值为1; preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));//给第五个占位符? 的值赋值为new Date(new java.util.Date().getTime()); //5.执行SQL int i = preparedStatement.executeUpdate(); if (i>0){ System.out.println("插入成功@"); } //6.关闭连接,释放资源(一定要做) 先开后关 preparedStatement.close(); connection.close(); } } 事务要么都成功,要么都失败!ACID原则:保证数据的安全。开启事务 事务提交 commit() 事务回滚 rollback() 关闭事务 转账: A:1000 B:1000 A(900) --100--> B(1100) Junit单元测试依赖<!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>简单使用@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!@Test public void test(){ System.out.println("Hello"); }![[(img-OsUubVNQ-1588757845424)(JavaWeb.assets/1568442261610.png)]](/usr/uploads/auto_save_image/df333138d8696914cc043efe81cf1c40.png)失败的时候是红色:![[(img-qv2oTEGI-1588757845425)(JavaWeb.assets/1568442289597.png)]](/usr/uploads/auto_save_image/05bc8e3d626d91daf31b62ef3b779101.png)搭建一个环境CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(40), money FLOAT ); INSERT INTO account(`name`,money) VALUES('A',1000); INSERT INTO account(`name`,money) VALUES('B',1000); INSERT INTO account(`name`,money) VALUES('C',1000); @Test public void test() { //配置信息 //useUnicode=true&characterEncoding=utf-8 解决中文乱码 String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; Connection connection = null; //1.加载驱动 try { Class.forName("com.mysql.jdbc.Driver"); //2.连接数据库,代表数据库 connection = DriverManager.getConnection(url, username, password); //3.通知数据库开启事务,false 开启 connection.setAutoCommit(false); String sql = "update account set money = money-100 where name = 'A'"; connection.prepareStatement(sql).executeUpdate(); //制造错误 //int i = 1/0; String sql2 = "update account set money = money+100 where name = 'B'"; connection.prepareStatement(sql2).executeUpdate(); connection.commit();//以上两条SQL都执行成功了,就提交事务! System.out.println("success"); } catch (Exception e) { try { //如果出现异常,就通知数据库回滚事务 connection.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }15、SMBMS(超市管理项目)完结
2022年04月18日
730 阅读
0 评论
0 点赞
2022-01-15
MySQL学习:SQL查询语句中select、 from、 where、 group by 、having、 order by的执行顺序
1. 字段解释from:需要从哪个数据表检索数据where:过滤表中数据的条件group by:如何将上面过滤出的数据分组having:对上面已经分组的数据进行过滤的条件select:查看结果集中的哪个列,或列的计算结果order by:按照什么样的顺序来查看返回的数据2.书写顺序与执行顺序书写顺序依次为:select>from>where>group by>having>order by # 其中select和from是必须的。执行顺序依次为:from>where>group by>having>select>order byfrom后面的表关联,是自右向左解析的;而where条件的解析顺序是从左往右的。也就是说,在写SQL语句的时候,尽量把数据量小的表放在最右边来进行关联(用小表去匹配大表),而把能筛选出小量数据的条件放在where语句的最左边 (用小表去匹配大表)。参考资料sql语句中select、 from、 where、 group by 、having、 order by的执行顺序分析SQL查询语句中select from where group by having order by的执行顺序
2022年01月15日
830 阅读
0 评论
0 点赞
2022-01-15
java学习:字符串的格式化及日期时间格式化
1. 常规类型格式化为字符串1.1 转换符转 换 符说 明示 例%s字符串类型"mingrisoft"%c字符类型'm'%b布尔类型true%d整数类型(十进制)99%x整数类型(十六进制)FF%o整数类型(八进制)77%f浮点类型99.99%a十六进制浮点类型FF.35AE%e指数类型9.38e+5%g通用浮点类型(f和e类型中较短的) %h散列码 %%百分比类型%%n换行符 %tx日期与时间类型(x代表不同的日期与时间转换符 1.2.使用案例public static void main(String[] args) { String str=null; str=String.format("Hi,%s", "王力"); System.out.println(str); str=String.format("Hi,%s:%s.%s", "王南","王力","王张"); System.out.println(str); System.out.printf("字母a的大写是:%c %n", 'A'); System.out.printf("3>7的结果是:%b %n", 3>7); System.out.printf("100的一半是:%d %n", 100/2); System.out.printf("100的16进制数是:%x %n", 100); System.out.printf("100的8进制数是:%o %n", 100); System.out.printf("50元的书打8.5折扣是:%f 元%n", 50*0.85); System.out.printf("上面价格的16进制数是:%a %n", 50*0.85); System.out.printf("上面价格的指数表示:%e %n", 50*0.85); System.out.printf("上面价格的指数和浮点数结果的长度较短的是:%g %n", 50*0.85); System.out.printf("上面的折扣是%d%% %n", 85); System.out.printf("字母A的散列码是:%h %n", 'A'); }输出结果Hi,王力 Hi,王南:王力.王张 字母a的大写是:A 3>7的结果是:false 100的一半是:50 100的16进制数是:64 100的8进制数是:144 50元的书打8.5折扣是:42.500000 元 上面价格的16进制数是:0x1.54p5 上面价格的指数表示:4.250000e+01 上面价格的指数和浮点数结果的长度较短的是:42.5000 上面的折扣是85% 字母A的散列码是:411.3 搭配的标志标 志说 明示 例结 果+为正数或者负数添加符号("%+d",15)+15−左对齐("%-5d",15)\15 \ 0数字前面补0("%04d", 99)0099空格在整数之前添加指定数量的空格("% 4d", 99)\99\ ,以“,”对数字分组("%,f", 9999.99)9,999.990000(使用括号包含负数("%(f", -99.99)(99.990000)#如果是浮点数则包含小数点,如果是16进制或8进制则添加0x或0("%#x", 99)("%#o", 99)0x63 0143<格式化前一个转换符所描述的参数("%f和%<3.2f", 99.45)99.450000和99.45$被格式化的参数索引("%1$d,%2$s", 99,"abc")99,abc1.4.使用案例public static void main(String[] args) { String str=null; //$使用 str=String.format("格式参数$的使用:%1$d,%2$s", 99,"abc"); System.out.println(str); //+使用 System.out.printf("显示正负数的符号:%+d与%d%n", 99,-99); //补O使用 System.out.printf("最牛的编号是:%03d%n", 7); //空格使用 System.out.printf("Tab键的效果是:% 8d%n", 7); //,使用 System.out.printf("整数分组的效果是:%,d%n", 9989997); //空格和小数点后面个数 System.out.printf("一本书的价格是:% 50.5f元%n", 49.8); }输出结果格式参数$的使用:99,abc 显示正负数的符号:+99与-99 最牛的编号是:007 Tab键的效果是: 7 整数分组的效果是:9,989,997 一本书的价格是: 49.80000元 2. 日期格式化2.1 转换符转 换 符说 明示 例%tx日期与时间类型(x代表不同的日期与时间转换符 c包括全部日期和时间信息星期六 十月 27 14:21:20 CST 2007F“年-月-日”格式2007-10-27D“月/日/年”格式10/27/07r“HH:MM:SS PM”格式(12时制)02:25:51 下午T“HH:MM:SS”格式(24时制)14:28:16R“HH:MM”格式(24时制)14:282.2 使用案例public static void main(String[] args) { Date date=new Date(); //c的使用 System.out.printf("全部日期和时间信息:%tc%n",date); //f的使用 System.out.printf("年-月-日格式:%tF%n",date); //d的使用 System.out.printf("月/日/年格式:%tD%n",date); //r的使用 System.out.printf("HH:MM:SS PM格式(12时制):%tr%n",date); //t的使用 System.out.printf("HH:MM:SS格式(24时制):%tT%n",date); //R的使用 System.out.printf("HH:MM格式(24时制):%tR",date); }输出结果全部日期和时间信息:星期一 九月 10 10:43:36 CST 2012 年-月-日格式:2012-09-10 月/日/年格式:09/10/12 HH:MM:SS PM格式(12时制):10:43:36 上午 HH:MM:SS格式(24时制):10:43:36 HH:MM格式(24时制):10:43public static void main(String[] args) { Date date=new Date(); //b的使用,月份简称 String str=String.format(Locale.US,"英文月份简称:%tb",date); System.out.println(str); System.out.printf("本地月份简称:%tb%n",date); //B的使用,月份全称 str=String.format(Locale.US,"英文月份全称:%tB",date); System.out.println(str); System.out.printf("本地月份全称:%tB%n",date); //a的使用,星期简称 str=String.format(Locale.US,"英文星期的简称:%ta",date); System.out.println(str); //A的使用,星期全称 System.out.printf("本地星期的简称:%tA%n",date); //C的使用,年前两位 System.out.printf("年的前两位数字(不足两位前面补0):%tC%n",date); //y的使用,年后两位 System.out.printf("年的后两位数字(不足两位前面补0):%ty%n",date); //j的使用,一年的天数 System.out.printf("一年中的天数(即年的第几天):%tj%n",date); //m的使用,月份 System.out.printf("两位数字的月份(不足两位前面补0):%tm%n",date); //d的使用,日(二位,不够补零) System.out.printf("两位数字的日(不足两位前面补0):%td%n",date); //e的使用,日(一位不补零) System.out.printf("月份的日(前面不补0):%te",date); }输出结果英文月份简称:Sep 本地月份简称:九月 英文月份全称:September 本地月份全称:九月 英文星期的简称:Mon 本地星期的简称:星期一 年的前两位数字(不足两位前面补0):20 年的后两位数字(不足两位前面补0):12 一年中的天数(即年的第几天):254 两位数字的月份(不足两位前面补0):09 两位数字的日(不足两位前面补0):10 月份的日(前面不补0):103.时间格式化3.1 转换符转 换 符说 明示 例H2位数字24时制的小时(不足2位前面补0)15I2位数字12时制的小时(不足2位前面补0)03k2位数字24时制的小时(前面不补0)15l2位数字12时制的小时(前面不补0)3M2位数字的分钟(不足2位前面补0)03S2位数字的秒(不足2位前面补0)09L3位数字的毫秒(不足3位前面补0)015N9位数字的毫秒数(不足9位前面补0)562000000p小写字母的上午或下午标记中:下午英:pmz相对于GMT的RFC822时区的偏移量+0800Z时区缩写字符串CSTs1970-1-1 00:00:00 到现在所经过的秒数1193468128Q1970-1-1 00:00:00 到现在所经过的毫秒数11934681289843.2 使用案例public static void main(String[] args) { Date date = new Date(); //H的使用 System.out.printf("2位数字24时制的小时(不足2位前面补0):%tH%n", date); //I的使用 System.out.printf("2位数字12时制的小时(不足2位前面补0):%tI%n", date); //k的使用 System.out.printf("2位数字24时制的小时(前面不补0):%tk%n", date); //l的使用 System.out.printf("2位数字12时制的小时(前面不补0):%tl%n", date); //M的使用 System.out.printf("2位数字的分钟(不足2位前面补0):%tM%n", date); //S的使用 System.out.printf("2位数字的秒(不足2位前面补0):%tS%n", date); //L的使用 System.out.printf("3位数字的毫秒(不足3位前面补0):%tL%n", date); //N的使用 System.out.printf("9位数字的毫秒数(不足9位前面补0):%tN%n", date); //p的使用 String str = String.format(Locale.US, "小写字母的上午或下午标记(英):%tp", date); System.out.println(str); System.out.printf("小写字母的上午或下午标记(中):%tp%n", date); //z的使用 System.out.printf("相对于GMT的RFC822时区的偏移量:%tz%n", date); //Z的使用 System.out.printf("时区缩写字符串:%tZ%n", date); //s的使用 System.out.printf("1970-1-1 00:00:00 到现在所经过的秒数:%ts%n", date); //Q的使用 System.out.printf("1970-1-1 00:00:00 到现在所经过的毫秒数:%tQ%n", date); }输出结果2位数字24时制的小时(不足2位前面补0):11 2位数字12时制的小时(不足2位前面补0):11 2位数字24时制的小时(前面不补0):11 2位数字12时制的小时(前面不补0):11 2位数字的分钟(不足2位前面补0):03 2位数字的秒(不足2位前面补0):52 3位数字的毫秒(不足3位前面补0):773 9位数字的毫秒数(不足9位前面补0):773000000 小写字母的上午或下午标记(英):am 小写字母的上午或下午标记(中):上午 相对于GMT的RFC822时区的偏移量:+0800 时区缩写字符串:CST 1970-1-1 00:00:00 到现在所经过的秒数:1347246232 1970-1-1 00:00:00 到现在所经过的毫秒数:1347246232773参考资料Java 字符串格式化详解JAVA字符串格式化-String.format()的使用java字符串格式化(String类format方法)
2022年01月15日
539 阅读
0 评论
0 点赞
2022-01-15
nginx学习:nginx的请求转发算法(负载均衡配置)
1.nginx支持的负载均衡调度算法1.1 轮询(默认算法):每个请求按时间顺序分配到不同后端服务器,如果某个后端服务器宕机,能自动剔除掉。基于iphttp { ..... 其他的内容 #定义上游服务器集群,定义一个负载均衡器 upstream myweb1 { server 192.168.0.161; server 192.168.0.162; server 192.168.0.163; } server { listen 80; location / { proxy_pass http://myweb1; } } }基于域名http { ..... 其他的内容 #定义上游服务器集群,定义一个负载均衡器 upstream myweb1 { server 192.168.0.161; server 192.168.0.162; server 192.168.0.163; } server { listen 80; server_name www.sc.com; location / { proxy_pass http://myweb1; } } }1.2 weight轮询nginx反向代理接受到客户端收到的请求后,可以给不同的后端服务器设置一个权重值(weight),用于调整不同服务器上请求的分配率,权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器配置进行配置的。比如说有些服务器的硬件配置高,比重就会比较大一点。http { ..... 其他的内容 #定义上游服务器集群,定义一个负载均衡器 upstream myweb1 { server 192.168.0.161 weight=1; server 192.168.0.162 weight=3; server 192.168.0.163 weight=6; } server { listen 80; server_name www.sc.com; location / { proxy_pass http://myweb1; } } }1.3 ip_hash每个请求按照发起客户端ip的hash结果进行匹配,这样的算法每一个固定的ip地址的客户端总会访问到同一个后端服务器,这也在一定程度上解决了集群部署环境下session共享的问题。http { ..... 其他的内容 #定义上游服务器集群,定义一个负载均衡器 upstream myweb1 { ip_hash; server 192.168.0.161; server 192.168.0.162; server 192.168.0.163; } server { listen 80; server_name www.sc.com; location / { proxy_pass http://myweb1; } } }1.4 least-connected–最小连接数将下一个请求分配给活动连接数量最少的服务器http { ..... 其他的内容 #定义上游服务器集群,定义一个负载均衡器 upstream myweb1 { least_conn; server 192.168.0.161; server 192.168.0.162; server 192.168.0.163; } server { listen 80; server_name www.sc.com; location / { proxy_pass http://myweb1; } } }1.5 fair:智能调整调度算法(第三方)动态的根据后端服务器的请求处理器的请求处理响应的时间来进行均衡分配,响应时间短,处理效率高的服务器分配到请求的概率高,响应时间长,处理效率低的服务器分配到的请求少;结合了前两者的优点的一种调度算法。但是需要注意的是nginx默认不支持fair算法,如果要使用这种算法,需要安装upstream_fair模块。1.6 url_hash(第三方)按照访问的url的hash结果分配请求,每个请求的url会指向后端固定的某个服务器,可以在nginx作为静态服务器的情况下提高缓存效率。同样要注意Nginx默认不支持这种调度算法,要使用的话需要安装nginx的hash软件包。http { ..... 其他的内容 #定义上游服务器集群,定义一个负载均衡器 upstream myweb1 { server 192.168.0.161; server 192.168.0.162; server 192.168.0.163; hash $request_uri; } server { listen 80; server_name www.sc.com; location / { proxy_pass http://myweb1; } } }在upstream模块中,可以通过server命令指定后端服务器的IP地址和端口,同时还可以设置每台后端服务器在负载均衡调度中的状态,常用的状态有以下几种:1、down:表示当前server暂时不参与负载均衡。2、backup:预留的备份机,当其他所有非backup机器出现故障或者繁忙的时候,才会请求backup机器,这台机器的访问压力最轻。3、max_fails:允许请求的失败次数,默认为1,配合fail_timeout一起使用4、fail_timeout:经历max_fails次失败后,暂停服务的时间,默认为10s(某个server连接失败了max_fails次,则nginx会认为该server不工作了。同时,在接下来的 fail_timeout时间内,nginx不再将请求分发给失效的server。)参考资料你知道nginx的请求转发算法,如何配置根据权重转发3. nginx的请求转发算法,如何配置根据权重转发Nginx负载均衡调度算法及配置案例Nginx几种负载均衡算法及配置实例Nginx配置之实现多台服务器负载均衡
2022年01月15日
643 阅读
0 评论
0 点赞
2022-01-15
java学习:Junit4单元测试的基本用法及注解和执行顺序
1. Junit最简单的用法案例新建一个类被测试类,里面包含一些测试方法package junit.util; /** * 被测试类,通过Junit对此类的方法进行单元测试 */ public class Claculate { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) { return a / b; } }新建一个Junit的测试类用来测试上面的测试方法,新增Junit的测试类方法如下:package junit.util; import static org.junit.Assert.*; import junit.util.Claculate; import org.junit.Test; /** * junit的测试方法必须使用@Test注解 * 测试方法必须以public void修饰,并且不包含参数 */ public class ClaculateTest { @Test public void testAdd() { /** * assertEquals这个方法是一个断言方法 * 第一个参数表示预期的结果 * 第二个参数表示程序的执行结果 * 当预期结果与执行结果是一致的时候,则表示单元测试成功 */ assertEquals(4, new Claculate().add(1, 3)); } @Test public void testSubtract() { assertEquals(4, new Claculate().subtract(9, 5)); } @Test public void testMultiply() { assertEquals(6, new Claculate().multiply(2, 3)); } @Test(expected=ArithmeticException.class) public void testDivide() { assertEquals(3, new Claculate().divide(9, 0)); } }上面的这个测试类,分别对被测试类Claculate的四个方法进行了测试,测试是选择使用Junit方式进行执行,如果想要执行单个测试方法,可以选择单个方法进行执行2.junit中的常用注解及执行顺序2.1 常用注解为什么引入注解?在实际项目中,进行JUnit测试时,通常会涉及到一些初始化的东西,可能有些配置项需要在测试前进行加载的,JUnit提供了一些初始化的方法用于初始化注解名作用@Before初始化方法,对于每一个测试方法都要执行一次(注意与BeforeClass区别,后者是对于所有方法执行一次)@After释放资源,对于每一个测试方法都要执行一次(注意与AfterClass区别,后者是对于所有方法执行一次)@Test测试方法,在这里可以测试期望异常和超时时间@Ignore忽略的测试方法@BeforeClass针对所有测试,只执行一次,且必须为static void@AfterClass针对所有测试,只执行一次,且必须为static void2.2 执行顺序一个JUnit4的单元测试用例执行顺序为:@BeforeClass -> @Before -> @Test -> @After -> @AfterClass; 每一个测试方法的调用顺序为:@Before -> @Test -> @After; 参考资料junit用法,before,beforeClass,after, afterClass的执行顺序Junit4单元测试的基本用法 Junit的基本使用(详解)
2022年01月15日
756 阅读
0 评论
0 点赞
2022-01-13
MySQL学习:常用函数总结
1.数学函数针对数字-- ABS(x) 返回x的绝对值 SELECT ABS(-1); -- 返回1 -- ROUND(x)返回离 x 最近的整数 SELECT ROUND(1.23456); -- 返回1 -- CEIL(x)/CEILING(x) 返回大于或等于 x 的最小整数 SELECT CEIL(1.5); -- 返回2 SELECT CEILING(1.5); -- 返回2 -- FLOOR(x) 返回小于或等于 x 的最大整数 SELECT FLOOR(1.5); -- 返回1 -- POW(x,y)/POWER(x,y)返回 x 的 y 次方 SELECT POW(2,3); -- 返回8 SELECT POWER(2,3); -- 返回8 -- RAND()返回 0 到 1 的随机数 SELECT RAND(); -- SIGN(x)返回 x 的符号,x 是负数、0、正数分别返回 -1、0 和 1 SELECT SIGN(-10); -- 返回-1 -- SQRT(x)返回x的平方根 SELECT SQRT(25); -- 返回5 -- TRUNCATE(x,y)返回数值 x 保留到小数点后 y 位的值,不会进行四舍五入 SELECT TRUNCATE(1.23456,3); -- 返回1.234针对字段-- AVG(expression) 返回一个表达式的平均值,expression 是一个字段 SELECT AVG(age) FROM student; -- MAX(expression)返回字段 expression 中的最大值 SELECT MAX(age) AS maxAge FROM Student; -- MIN(expression)返回字段 expression 中的最大值 SELECT MIN(age) AS minAge FROM Student; -- SUM(expression)返回指定字段的总和 SUM(expression)返回指定字段的总和2.字符串函数-- LENGTH/CHAR_LENGTH(s)/CHARACTER_LENGTH(s)返回字符串 s 的字符数 SELECT LENGTH('1234'); -- 返回4 -- CONCAT(s1,s2…sn)字符串 s1,s2 等多个字符串合并为一个字符串 SELECT CONCAT('hel','llo'); -- 返回hello -- LOCATE(s1,s)从字符串 s 中获取 s1 的开始位置 SELECT LOCATE('st','myteststring'); -- 返回5 -- LCASE(s)/LOWER(s)将字符串 s 的所有字母变成小写字母 SELECT LOWER('RUNOOB'); -- 返回runoob -- UCASE(s)/UPPER(s)将字符串 s 的所有字母变成大写字母 SELECT UCASE('runoob'); -- 返回RUNOOB -- TRIM(s)去掉字符串 s 开始和结尾处的空格 SELECT TRIM(' RUNOOB ');-- 返回RUNOOB -- SUBSTR/SUBSTRING(s, start, length)从字符串 s 的 start 位置截取长度为 length 的子字符串 SELECT SUBSTR/SUBSTRING("RUNOOB", 2, 3);-- 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符,返回UNO -- REVERSE(s)将字符串s的顺序反过来 SELECT REVERSE('abc');-- 返回cba -- REPLACE()替换出现的指定字符串 SELECT REPLACE('狂神说坚持就能成功','坚持','努力'); -- 替换出现的指定字符串 SELECT REPIACE(studentname,'周','邹') FROM student WHERE studentname LIKE '%周';3.时间日期函数-- CURDATE()/CURRENT_DATE()返回当前日期 SELECT CURDATE();-- 返回2019-02-19 SELECT CURRENT_DATE(); -- 返回2019-02-19 -- CURRENT_TIME()/CURTIME()返回当前时间 SELECT CURRENT_TIME(); -- 返回11:40:45 -- NOW()返回当前日期和时间 SELECT NOW();-- 返回2019-02-19 11:41:32 SELECT LOCALTIME(); -- 本地时间 SELECT SYSDATE(); -- 系统时间 -- 提取年月日时分秒 SELECT YEAR(NOW()); SELECT MONTH(NOW()); SELECT DAY(NOW()); SELECT HOUR(NOW()); SELECT MINUTE(NOW()); SELECT SECOND(NOW());4.系统函数-- CURRENT_USER()/SESSION_USER()/SYSTEM_USER()/USER()返回当前用户 SELECT USER(); -- DATABASE()返回当前数据库名 SELECT DATABASE(); -- VERSION()返回数据库的版本号 SELECT VERSION();参考资料MySQL 5.7 参考手册12.6 数值函数和运算符12.8 字符串函数和运算符12.7 日期和时间函数MySQL常用函数大全(总结篇)
2022年01月13日
610 阅读
0 评论
0 点赞
2022-01-13
MySQL学习:SQL关联查询的七种JOIN
1.图示2.案例2.0 准备数据以一个简易问答系统为例,包括问题表和问题所属标签,问题表如下:CREATE TABLE `t_qa` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL DEFAULT '' COMMENT '标题', `answer_count` int(5) unsigned NOT NULL DEFAULT '0' COMMENT '回答个数', `label_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '标签id', `create_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建人', `create_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间', `update_by` bigint(20) unsigned DEFAULT NULL COMMENT '更新人', `update_date` datetime DEFAULT NULL COMMENT '更新时间', `del_flag` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0:不删除,1:删除', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `t_qa` (`id`, `title`, `answer_count`, `label_id`, `create_by`, `create_date`, `update_by`, `update_date`, `del_flag`) VALUES (1, 'Java是什么?', 5, 1, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (2, 'PHP是什么?', 4, 2, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (3, '前端是什么?', 3, 3, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (4, 'nodejs是什么?', 2, 0, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (5, 'css是什么?', 1, 0, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (6, 'JavaScript是什么?', 0, 0, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0);标签表如下:CREATE TABLE `t_label` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称', `create_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建人', `create_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间', `update_by` bigint(20) unsigned DEFAULT NULL COMMENT '更新人', `update_date` datetime DEFAULT NULL COMMENT '更新时间', `del_flag` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0:不删除,1:删除', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `t_label` (`id`, `name`, `create_by`, `create_date`, `update_by`, `update_date`, `del_flag`) VALUES (1, 'java', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (2, 'php', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (3, '大前端', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (4, 'mybatis', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (5, 'python', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0), (6, '多线程', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0);2.1 左连接(LEFT JOIN)问题回答个数标签id标签名称Java是什么?51javaPHP是什么?42php前端是什么?33大前端nodejs是什么?2NULLNULLcss是什么?1NULLNULLJavaScript是什么?1NULLNULLSELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.id2.2 右连接(RIGHT JOIN)问题回答个数标签id标签名称Java是什么?51javaPHP是什么?42php前端是什么?33大前端NULLNULL4mybatisNULLNULL5pythonNULLNULL6多线程SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id2.3 内连接(INNER JOIN)问题回答个数标签id标签名称Java是什么?51javaPHP是什么?42php前端是什么?33大前端SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq INNER JOIN t_label tl ON tq.label_id = tl.id2.4 左独有连接(LEFT JOIN)问题回答个数标签id标签名称nodejs是什么?2NULLNULLcss是什么?1NULLNULLJavaScript是什么?0NULLNULLSELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.id WHERE tl.id IS NULL2.5 右独有连接(RIGHT JOIN)问题回答个数标签id标签名称NULLNULL4mybatisNULLNULL5pythonNULLNULL6多线程SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id WHERE tq.label_id IS NULL2.6 全连接(FULL JOIN)由于MySQL不支持FULL OUTER JOIN,所以如果有全连接需求时,可用表达式:full outer join = left outer join UNION right outer join来实现。问题回答个数标签id标签名称Java是什么?51javaPHP是什么?42php前端是什么?33大前端nodejs是什么?2NULLNULLcss是什么?1NULLNULLJavaScript是什么?0NULLNULLNULLNULL4mybatisNULLNULL5pythonNULLNULL6多线程SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.id UNION SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id 2.7 全连接去交集(FULL JOIN)问题回答个数标签id标签名称nodejs是什么?2NULLNULLcss是什么?1NULLNULLJavaScript是什么?0NULLNULLNULLNULL4mybatisNULLNULL5pythonNULLNULL6多线程SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.id WHERE tl.id IS NULL UNION SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id WHERE tq.label_id IS NULL参考资料一张图看懂 SQL 的各种 JOIN 用法SQL七种JOIN解析【MySQL笔记】七种JOIN的SQL
2022年01月13日
858 阅读
0 评论
0 点赞