1)在我们真正进行WEB开发的时候,编写代码之前,我们都要做两件非常重要的设计:数据库设计+前后端交互API接口的设计+JDBC操作+WEB服务器开发能力,我们还要实现一个简单的页面来进行展示当前的图片

2)学习测试服务器---->PostMan

1.项目背景:首先它是一个服务器(图床)

1)核心功能:上传图片,展示图片

2)我们通常会写博客,githup,可能我们也是会穿插图片或者其他资源,我们写博客的时候,插入的图片,本质上就是一个url,这个链接所对应的图片资源在另一个服务器上面,本质上CSDN已经内置了这个图片服务器功能

3)当我们在浏览器上面输入图片的时候,我们点击这个图片,复制链接地址,然后再来打开一个浏览器的窗口,输入刚才的这个链接地址,展示搜索结果,我们就可以看到这个图片了

2.核心知识点:

1)简单的Web服务器(HTTP服务器)设计开发能力(Servlet)

2)Servlet是Tomact这个服务器提供的一组编程接口,我们就可以开发出我们自己所实现的一套逻辑,这一套逻辑我们就可以部署到Tomact里面,就可以完成一个我们自己的服务器的搭建

3)使用数据库进行存储

4)学会设数据库设计,根据实际场景设计数据库表结构

5)前后端接口的设计,前后端交互的API的设计

6)认识JSON数据格式,使用Gson这个库来进行操作JSON

7)学习测试一个服务器(postman),使用HTML,CSS,javascript来进行构建一个简单的网页

3.服务器设计和数据库设计

1)mysql -uroot连接数据库,就是启动了MYSQL客户端,我们之前安装数据库,即安装了服务器又安装了客户端(命令行程序),是同过网络来进行通信的

2)MYSQL服务器就是我们的本体,在这个服务器里面包含着数据库和表;

3)MariaDB和MYSQL有什么关系?

4)创建表结构:

描述图片相关的内容(属性信息)

1)ImageID 图片ID primary key auto_increment----图片的唯一身份标识

2)ImageName varchar(50)------图片的名字

3)ImageSize int------图片的大小

4)ImageTime varchar(50)------图片的上传时间

5)ContentType varchar(50)---->image/jpg

(ContentType(HTTP数据类型)=image/png)-----表示图片类型

6)ContentPath varchar(50)--------路径,服务器本地的目录

7)md5 varchar(1024)------校验和(在应用层进行校验)

咱们的数据库中存储的是图片的属性和路径;

图片正文,是以文件的形式直接存储在磁盘里面的,数据库中的一个Contentpath就是对应咱们磁盘上面的文件

md5:字符串哈希算法,密码学领域也能用到

1)图片的MD5校验和,应用层进行数据校验,通过一个更短的字符串来进行验证整体数据是否正确,短的字符串是根据源字符串的内容按照一定的规则来计算出来的;

2)src循环冗余校验算法

3)哈希算法就是把key经过一系列的数学变换,得到一个整数,对应到数组下标上面,把hello字符串计算出一个哈希值(123456),把这个哈希值去%数组的长度从而得到数组下标

4.服务器API设计:

JSON是一种数据组织的格式,格式是键值对的结构,gson既可以解析哈希表也是可以进行解析类的,还可以解析数组;

第一种用法:把哈希表转化成JSON格式的数据

对于对象来说,转化成JSON格式的数据键就是字段名,Value就是这个字段对应的值

引入2.8.6的库
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
public class TestJson {public static void main(String[] args) {HashMap<String,Object> hashMap=new HashMap<>();//1.创建hashmaphashMap.put("name","曹操");hashMap.put("代码大神","李佳伟");//2创建Json对象Gson gson=new GsonBuilder().create();//3.使用ToGson方法转成字符串String str= gson.toJson(hashMap);//里面的参数也可以是一个对象System.out.println(str);}
}

第二种用法:使用数组

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class TestJson {static class Student{public String username;public int age;public String password;}public static void main(String[] args) {Student student1=new Student();student1.age=12;student1.username="李佳伟";student1.password="12503487";Student student2=new Student();student2.age=12;student2.username="周云刚";student2.password="778896";List<Student> list=new ArrayList<>();list.add(student1);list.add(student2);Gson gson=new GsonBuilder().create();String str= gson.toJson(list);System.out.println(str);}
}

回顾:文件上传操作在HTML中是如何完成的

1)我们直接在前端使用form表单

  <form action="upload" method="POST" enctype="multipart/form-data"><input type="file" name="MyImage"><input type="submit" value="提交图片"></form>
1)这里面的ID就表示唯一的身份标识
2)action:提交图片的时候,产生的HTTP请求产生的Path是怎么样的,url
3)method:GET方法上传还是POST方法上传
4)enctype:表示请求的格式,文件的传输格式

我们开始正式设计前后端进行交互的API:HTTP协议具体要构造成什么样子

1)新增图片:

请求:
POST/Image
ContentType:multipart/form-data;正文内容:包含图片自身的一些信息,图片正文的二进制内容响应:
1)上传成功的情况:
HTTP/1.1 200 OK
{OK:"1",reason:"上传成功"
}
2)上传失败的情况:
HTTP/1.1 200 OK
{OK:"0",reason:"上传图片失败"
}

2)查看所有图片信息(数据库存放的属性信息)

请求:
GET/Image响应:
HTTP/1.1 200 OK
[{ImageID:1,ImageName:"代码.png",ImageSize:1000,ImageTime:"2022/12/2",ContentType:"image/png",ContentPath:"./data/1.png",md5:"1122334455"},{ImageID:2,ImageName:"板书.png",ImageSize:1050,ImageTime:"2022/10/2",ContentType:"image1/png",ContentPath:"./data/2.png",md5:"778896"}
]
获取失败:
HTTP/1.1 200 OK
[]

3)查看指定图片信息

请求:
GET/Image?ImageID=7
响应:HTTP/1.1 200 OK
{ImageID:1,ImageName:"代码.png",ImageSize:1000,ImageTime:"2022/12/2",ContentType:"image/png",ContentPath:"./data/1.png",md5:"1122334455"}
响应失败:
HTTP/1.1 200 OK
{OK:"0",reason:"失败的原因"
}

4)删除操作(删除指定图片)

请求:
DELETE/Image?ImageID=具体的图片ID
响应:
HTTP/1.1 200 OK
{OK:"200",reason:""
}
响应失败:
HTTP/1.1 200 OK
{ OK:"200",reason:"出错原因",
}

6)查看指定图片内容(咱们的图片内容到底展示的是小猫小狗,还是其他呢?)

请求:GET/ImageShow?ImageID=1响应:HTTP/1.1 200 OK
ContentType:image/jpg[图片的二进制内容]返回错误:
HTTP/1.1 200 OK
{OK:"200",reason:"出错的原因"
}

我们总共拆分成了两个Servlet,一个路径请求对应着一个Servlet

源码开发:

一:封装获取到数据库连接操作

create table Image(ImageID int primary key auto_increment,ImageName varchar(100),ImageSize int,ImageTime dateTime,ContentType varchar(50),ContentPath varchar(100),md5 varchar(100));
此时咱们的数据库是在linux上面进行运行的,咱们要在数据库中进行创建表
package Dao;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ConnectionMysql {private static  volatile DataSource dataSource=null;private static String url="jdbc:mysql://127.0.0.1:3306/picturemaven?characterEncoding=utf-8&userSSL=true";private static String username="root";private static String password="12503487";private static DataSource GetDataSource(){if(dataSource==null){synchronized(Object.class){if(dataSource==null){dataSource=new MysqlDataSource();((MysqlDataSource)dataSource).setPassword(password);((MysqlDataSource)dataSource).setUser(username);((MysqlDataSource)dataSource).setURL(url);}}}return dataSource;}public static Connection GetConnection() throws SQLException {return GetDataSource().getConnection();}public static void Close(ResultSet resultSet, PreparedStatement preparedStatement,Connection connection) throws SQLException {if(resultSet!=null){resultSet.close();}if(preparedStatement!=null){preparedStatement.close();}if(connection!=null){connection.close();}}
}

1)多个线程同时操作一个数据的时候,可能会发生线程安全问题

1.1)当我们进行创建datasource实例的时候,进入if语句之后,可能就是说第一个线程在进行new datasource()实例的时候(datasource实例,马上就要进行创建了),可能线程2在这个时候会抢占CPU,到就绪队列上面执行;

1.2)当第二个线程进行读取(进入到if语句判断里面)发现datasource是空(此时线程1还没有创建DataSource实例,就被线程2抢走了,线程2会立即执行创建dataSource实例),就会创建第一份datasource实例,当我们的线程1被调度上CPU执行之后(if语句因为调度被线程2抢走之前已经判断为空了,PCB的上下文此时就会发生作用),又会进行创建datasource对象,从而导致线程不安全问题

2)资源关闭顺序一定要正确(后创建的先进行释放)

3)咱们的ctrl+alt+t surround功能是选中一部分代码之后,在这个代码外边加上一些其他代码

4)加上volatile关键字之后就可以防止线程1创建DataSource实例之后,线程2也想创建DataSource,无法感知线程1已经创建了DataSource实例,还认为DataSource为空呢,进行外层if判断的时候可能会导致判断错误

这个程序会报错,数据库会无法连接

二:封装数据库操作数据

受查异常:向上抛出或者是就地处理

出现异常之后的处理措施:

1)直接用catch进行捕获,里面直接打印信息调用栈

2)直接抛出异常,让我们的程序进行终止

3)监控报警直接通知程序员,这个一般适用于服务器,我们就去专门写一个程序,它是用来感知服务器是否出现了问题,一旦我们的程序发生了问题,那么直接发送短信/电话/微信(比如说充钱操作)

Java代码封装数据库:

1)创建一个Image对象,对应一个图片对象(包括图片的相关属性),这一个类就对应着一张数据库的表(里面的path属性就表示我们的图片位置在我们的计算机硬盘上面的哪一个位置),咱们的数据库只是存放图片的属性,而咱们具体的图片内容是存放在一个个的文件里面;

package Dao;public class Image {private int ImageID;private String ImageName;private int ImageSize;private String ImageTime;private String ConteneType;private String ContentPath;private String md5;public int getImageID() {return ImageID;}public void setImageID(int imageID) {ImageID = imageID;}public String getImageName() {return ImageName;}public void setImageName(String imageName) {ImageName = imageName;}public int getImageSize() {return ImageSize;}public void setImageSize(int imageSize) {ImageSize = imageSize;}public String getImageTime() {return ImageTime;}public void setImageTime(String imageTime) {ImageTime = imageTime;}public String getConteneType() {return ConteneType;}public void setConteneType(String conteneType) {ConteneType = conteneType;}public String getContentPath() {return ContentPath;}public void setContentPath(String contentPath) {ContentPath = contentPath;}public String getMd5() {return md5;}public void setMd5(String md5) {this.md5 = md5;}@Overridepublic String toString() {return "Image{" +"ImageID=" + ImageID +", ImageName='" + ImageName + '\'' +", ImageSize=" + ImageSize +", ImageTime='" + ImageTime + '\'' +", ConteneType='" + ConteneType + '\'' +", ContentPath='" + ContentPath + '\'' +", md5='" + md5 + '\'' +'}';}
}

2)我们在进行创建一个包叫做ImageDemo,在进行创建一个类叫做OperateImage对象的管理器,我们希望借助这个类完成对对象的增删改查

2.1)当我们进行新增一个Image对象的时候,实现这个方法的时候,我们在方法里面直接传入一个Image对象,进行插入数据库里面

2.2)进行查找的时候,我们要分成两种情况,一种是查询所有的图片(List<Image>,一种是查找指定ID的图片(Image)

2.3)删除操作,是指定图片的ID进行删除,ImageID:

package Dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class OperateImage {public void InsertImage(Image image) throws SQLException, JavaOperateMysql {//1与数据库建立连接Connection connection=ConnectionMysql.GetConnection();//2.创建并拼装SQL语句String Sql="insert into Image values(null,?,?,?,?,?,?)";PreparedStatement preparedStatement=connection.prepareStatement(Sql);preparedStatement.setString(1,image.getImageName());preparedStatement.setInt(2,image.getImageSize());preparedStatement.setString(3,image.getImageTime());preparedStatement.setString(4,image.getConteneType());preparedStatement.setString(5,image.getContentPath());preparedStatement.setString(6,image.getMd5());//3.执行SQL语句int len=preparedStatement.executeUpdate();if(len==1){System.out.println("插入图片的操作成功");}else{System.out.println("插入图片的操作失败");//  throw new UnsupportedOperationException("当前数据库执行插入操作失败");throw new JavaOperateMysql("当前数据库插入操作失败");
当我们的程序写到这里的时候,还是会发生问题,当我们上面的任意一个操作抛出异常的时候
就会直接自己跳转到Catch语句或者是程序异常终止
所谓一我们后面的关闭资源的操作就有可能执行失败,我们根本的目的就是无论程序是否出现异常,我们都要进行最终的一个资源关闭操作
所以最好好把关闭资源的操作放到finally里面,程序的代码可能会爆红,我们就把代码字段变成全局变量}//4.关闭连接ConnectionMysql.Close(null,preparedStatement,connection);}public List<Image> SelectAll() throws SQLException {//1.与数据库建立连接Connection connection=ConnectionMysql.GetConnection();//2.拼装SQL语句String SQL="select * from Image";//3.执行SQL语句PreparedStatement preparedStatement= connection.prepareStatement(SQL);ResultSet resultSet= preparedStatement.executeQuery();List<Image> list=new ArrayList<>();//4.遍历结果集,返回结果while(resultSet.next()){Image image=new Image();image.setImageID(resultSet.getInt("ImageID"));image.setContentPath(resultSet.getString("ContentPath"));image.setImageTime(resultSet.getString("ImageTime"));image.setMd5(resultSet.getString("md5"));image.setImageSize(resultSet.getInt("ImageSize"));image.setImageName(resultSet.getString("ImageName"));image.setConteneType(resultSet.getString("ContentType"));System.out.println(image);list.add(image);}//5.关闭连接ConnectionMysql.Close(resultSet,preparedStatement,connection);return list;}public Image SelectOne(int ImageID) throws SQLException {//1.与数据库建立连接Connection connection=ConnectionMysql.GetConnection();//2.拼装SQL语句String sql="select * from Image where ImageID=?";//3.执行SQL语句PreparedStatement preparedStatement= connection.prepareStatement(sql);preparedStatement.setInt(1,ImageID);ResultSet resultSet= preparedStatement.executeQuery();//4.处理结果集Image image=new Image();while(resultSet.next()){image.setImageID(resultSet.getInt("ImageID"));image.setContentPath(resultSet.getString("ContentPath"));image.setImageTime(resultSet.getString("ImageTime"));image.setMd5(resultSet.getString("md5"));image.setImageSize(resultSet.getInt("ImageSize"));image.setImageName(resultSet.getString("ImageName"));image.setConteneType(resultSet.getString("ContentType"));}ConnectionMysql.Close(resultSet,preparedStatement,connection);return image;}public void Delete(int ImageID) throws SQLException {//1.与数据库建立连接Connection connection=ConnectionMysql.GetConnection();//2.拼装SQL语句String SQL ="delete from Image where ImageID=?";//3.执行SQL语句PreparedStatement preparedStatement=connection.prepareStatement(SQL);int len= preparedStatement.executeUpdate();if(len==1){System.out.println("删除成功");}else{System.out.println("删除失败");}//4.关闭资源ConnectionMysql.Close(null,preparedStatement,connection);}
}

如何进行打JAR包:

1.普通方法:

1)注意:当前我们的数据库是在阿里云服务器上面,也就是在咱们的linux上面,不是在本地的windows系统上面,我们直接通过上述代码是不可以进行直接在本地访问咱们的数据库,所以我们需要把这些程序部署到我们的云服务器上面才可以看到效果

2)我们的解决方法就是直接打一个jar包,我们直接把这个jar包直接拷贝到我们的云服务器上面就可以了

3)我们直接点击File目录中的Project Structure会显示Project Setting,然后我们直接点击Artifacts,然后在进行点击+,点击jar,在进行点击mainclass,选择我们的入口类(表示要从哪一个类开始执行)(这个入口类必须有main方法)

4)JAR包:本质上来说就是一个zip压缩包,本质上来说就是一大堆的.class文件,我们会把一大堆的.class文件放在一起,打包成一个文件

5)最后我们点击Build点击BuildAtifacts就可以进行打包操作了,打包之后,就会自动生成jar包

6)先把jar包拖到linux上面,运行我们的jar包:java -jar +jar包名字,我们就可以进行运行jar包了,我们按下回车之后,系统虽然没有给任何的提示,但是如果说最后咱们的jar包运行错误,那么一定会抛出一个异常,会打印异常调用栈的信息

下面是我写代码的时候出现的两个错误

 while(resultSet!=null){Image image=new Image();image.setImageID(image.getImageID());image.setContentPath(image.getContentPath());image.setImageTime(image.getImageTime());image.setMd5(image.getMd5());image.setConteneType(image.getConteneType());}
//1.第一个判定条件是result.next
//2.第二个写的啥也不是,具体的值应该从result中获取

我们可以通过单元测试的方法对程序进行验证,所谓的单元测试,就是把一个类或者是一个方法作为一个单元,一旦出现问题,我们就可以尽早地发现BUG,BUG发现的越早,我们的解决成本就越低 

零基础编写图片服务器(1)相关推荐

  1. php 动态彩码辨色 接口的调用_好用的云函数!后端低代码接口开发,零基础编写API接口...

    前言 在开发项目过程中,经常需要用到API接口,实现对数据库的CURD等操作. 不管你是专业的PHP开发工程师,还是客户端开发工程师,或者是不懂编程但懂得数据库SQL查询,又或者是完全不太懂技术的人, ...

  2. 好用的云函数!后端低代码接口开发,零基础编写API接口

    前言 在开发项目过程中,经常需要用到API接口,实现对数据库的CURD等操作. 不管你是专业的PHP开发工程师,还是客户端开发工程师,或者是不懂编程但懂得数据库SQL查询,又或者是完全不太懂技术的人, ...

  3. 【MC】我的世界零基础开云服务器教程

    [MC]我的世界零基础开云服务器教程 文章目录 [MC]我的世界零基础开云服务器教程 前言 一.需要用到的软件及网站 二.在本地开服务器 1.安装Java 2.在本地运行服务端 三.云服务器 1. 创 ...

  4. [零基础]从购买服务器到编程使用公网ip实现简单通信

    目录 前言 步骤 一.实现思路 二.配置服务器 服务器选购 登录服务器 三.开放端口 1.设置安全组 2.开放服务器系统防火墙 四.实机演练 1.源码和应用程序资源 2.配置软件所需文件 3.调试程序 ...

  5. 零基础编写一个串口网络调试助手(一)

    摘要:作为一名嵌入式开发行者QT是必须要学的,也许现在不学以后也要学习的.一方面,在嵌入式初学阶段,也就是裸机开发,可能需要自己写上位机,QT就是一个做上位机的一个好用的工具,一般只要会c++学习QT ...

  6. 零基础编写操作系统系列——电脑自启动hello world

    编写操作系统的第一步,就是让自己写在软盘上的系统自启动 ps:本次程序运行在虚拟机上 开发工具(评论留邮箱发) 第一步 新建一个文件夹,为了方便起见,就为project1吧 在该文件夹里新建一个文本文 ...

  7. 006永磁电机永磁体的类型:何为凸极性、隐极性,表贴式、内置式,傻瓜式讲解,专为零基础编写。

    从电机的命名上大家也可以看出来, 之所以叫永磁电机, 是因为该电机的的转子上是永磁体, 不同于其他电机通过线圈通电产生磁场产生转动力矩. 永磁体在转子上的不同布置, 会导致内部磁场的特性有所不同, 常 ...

  8. Django2.0服务器的零基础完全部署

    此文完全针对小白和零基础,大佬和有经验的司机请直接忽视略过,因为太过啰嗦!打扰了(^_^)Biu~ Biu~  开始~~ ---RedPanda 配置环境介绍 本地环境:windows10 home版 ...

  9. python 二进制流转图片_Python零基础入门到精通-5.1节:Python程序的执行过程

    教程引言: 系统地讲解计算机基础知识,Python的基础知识, 高级知识,web开发框架,爬虫开发,数据结构与算法,nginx, 系统架构.一步步地帮助你从入门到就业. 5.1.1 在命令行中执行Py ...

最新文章

  1. Mac下Jenkins+SVN+Xcode构建持续
  2. Matlab实用程序--图形应用-图形标注
  3. Python 创建随机名字的文件夹/文件
  4. 《剑指offer》数据流中的中位数
  5. 建立Win32 Console Project时会出“error LNK1123” 错误
  6. 基于环境气象因素影响的异常就诊量预测
  7. 用户管理实用命令(第二版)
  8. 收藏 | 从SGD到NadaMax,深度学习十种优化算法原理及实现
  9. sqlplus登录问题
  10. 报纸、电商、PC互联网颠覆传统行业,带来新的生态,自媒体也一样
  11. 学html需要什么软件,在上海学html需要学什么软件?
  12. java.lang.UnsatifiedLinkError错误一例:不同虚拟机之间的库不能共用
  13. ecshop 实现购物车退出不清空
  14. IaaS基础架构云 —— 云网络
  15. Marlin固件配置教程详解
  16. 《七哥说道》第十三章:我的室友白羽鸡
  17. PTA 7-10 查询水果价格
  18. 自定义线程池拒绝策略缓解高并发下线程池压力
  19. 已知分布函数求概率密度例题_高中数学必修一函数知识点总结
  20. SEO魔法书-网站优化

热门文章

  1. 习题整理——二叉树NOI1758、UVA679、UVA122
  2. 3D种类游戏系统开发
  3. python和stata怎么结合_双剑合璧之Stata与Python:初识IPyStata
  4. 轮廓线扫描算法:Theo Pavlidis' Algorithm
  5. [转清华]清华,曾经是多少莘莘学子梦想中的学府……张琳
  6. rocket使用实例
  7. CentOS发行版本与内核版本对应关系
  8. 思科ISR4400交换机查看光模块光功率
  9. 二叉树之前序遍历、中序遍历、后续遍历
  10. 布雷顿森林体系的前因后果