当前位置: 首页 > news >正文

web人脸登录

1,需要腾讯人脸第三方
腾讯人脸第三方申请步骤
2,相关表结构设计

create database faceDB;use faceDB;
-- 人脸表
create table face(
fid int primary key auto_increment COMMENT '主键',
face_base longtext COMMENT '图片数据 base_64编码',
create_time datetime COMMENT '插入时间',
vef_num int COMMENT '验证次数',
face_name varchar(100) COMMENT '人脸名称',
remark varchar(200) COMMENT '人脸备注',
face_status int COMMENT '人脸是否可用,(0==可用,1,不可用)',
update_extend1 varchar(300) COMMENT '扩展字段1',
update_extend2 varchar(300) COMMENT '扩展字段2',
update_extend3 varchar(300) COMMENT '扩展字段3'
);
-- 验证日志表
create table face_vef_log(
lid int primary key auto_increment COMMENT '主键',
vef_time datetime COMMENT '验证时间',
vef_code int COMMENT '返回code',
vef_msg varchar(200) COMMENT '返回的消息',
login_name varchar(100) COMMENT '验证人'
);

3,相关配置

tencentcloudapi:# 你的 secretIdsecretId: 你腾讯云的secretId# 你的 secretKeysecretKey: 你腾讯云的secretKey# 请求官方地址 不变endpoint: iai.tencentcloudapi.com#地域 可不变region: ap-shanghai
package com.face.config;import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.face.utils.JwtUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;/*** @author tanyongpeng* <p>des</p>**/
@Component
@Slf4j
public class FaceConfig implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String face_token = request.getHeader("face_token");Map<String,Object> infoMap = new HashMap<>();try{//token验证DecodedJWT tokenInfo = JwtUtils.getTokenInfo(face_token);//添加返回信息infoMap.put("msg","验证成功");return true;}catch (SignatureVerificationException e){e.printStackTrace();infoMap.put("msg","无效签名");}catch (TokenExpiredException e){infoMap.put("msg","token已过期");}catch (AlgorithmMismatchException e){infoMap.put("msg","算法不一致");}catch (Exception e){infoMap.put("msg","无效签名");}ObjectMapper objectMapper = new ObjectMapper();String mapInfoJson = objectMapper.writeValueAsString(infoMap);response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");PrintWriter writer = response.getWriter();writer.write(mapInfoJson);return false;}
}
package com.face.server;import com.face.bean.result.FaceResult;
import com.face.utils.TimeUtils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iai.v20180301.IaiClient;
import com.tencentcloudapi.iai.v20180301.models.CompareFaceRequest;
import com.tencentcloudapi.iai.v20180301.models.CompareFaceResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.util.HashMap;
import java.util.Map;/*** @author tanyongpeng* <p>调用腾讯接口</p>**/
@Component
@Data
@Slf4j
public class FaceContrastServer {@Value("${tencentcloudapi.secretId}")private String secretId;@Value("${tencentcloudapi.secretKey}")private String secretKey;@Value("${tencentcloudapi.endpoint}")private String endpoint;@Value("${tencentcloudapi.region}")private String region;//第一张是数据库图片,第二张是登录时验证图片public FaceResult faceContrast(String imageA, String imageB){FaceResult faceResult = new FaceResult();try{Credential cred = new Credential(secretId, secretKey);HttpProfile httpProfile = new HttpProfile();httpProfile.setEndpoint(endpoint);ClientProfile clientProfile = new ClientProfile();clientProfile.setHttpProfile(httpProfile);IaiClient client = new IaiClient(cred, region, clientProfile);CompareFaceRequest req = new CompareFaceRequest();req.setImageA(imageA);req.setImageB(imageB);CompareFaceResponse resp = client.CompareFace(req);faceResult.setScore(resp.getScore());faceResult.setCode(FaceResult.SUCCESS_CODE);} catch (TencentCloudSDKException e) {faceResult.setCode(FaceResult.FACE_ERROR);faceResult.setMsg(e.getMessage());}return faceResult;}
}

4,人脸注册,登录后端代码

package com.face.service.impl;import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.face.bean.Face;
import com.face.bean.result.FaceResult;
import com.face.mapper.FaceMapper;
import com.face.server.FaceContrastServer;
import com.face.service.FaceService;
import com.face.utils.JwtUtils;
import com.face.utils.TimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/**
* @author typsusan
* @description 针对表【face】的数据库操作Service实现
* @createDate 2022-07-17 03:33:50
*/
@Service
public class FaceServiceImpl extends ServiceImpl<FaceMapper, Face>implements FaceService {@AutowiredFaceContrastServer faceContrastServer;@Overridepublic FaceResult vef(String imageBase) {imageBase = JSONUtil.parseObj(imageBase).getStr("imageBase");List<Face> faceList = lambdaQuery().orderByDesc(Face::getVefNum).list();FaceResult faceState = null;// 如果人脸库为空,则第一次登录为录入人脸if (faceList.size() == 0){return initFace(imageBase);}else {int faceLength = faceList.size();for (Face face : faceList) {FaceResult faceResult = faceContrastServer.faceContrast(face.getFaceBase(), imageBase);// 是否比对成功if (faceResult.getCode() == FaceResult.SUCCESS_CODE ){// 相似度是否大于80if (faceResult.getScore() > FaceResult.SATISFY_SCORE){if (face.getFaceStatus() == 0){// 成功lambdaUpdate().set(Face::getVefNum,face.getVefNum()+1).eq(Face::getFid,face.getFid()).update();faceResult.setMsg(TimeUtils.timeQuantum()+"好,"+face.getFaceName());faceResult.setName(face.getFaceName());Map<String,String> map = new HashMap<>();map.put("score",String.valueOf(faceResult.getScore()));map.put("faceName",faceResult.getName());faceResult.setToken(JwtUtils.genereteToken(map));return faceResult;}else {// 失败 人脸被禁用lambdaUpdate().set(Face::getVefNum,face.getVefNum()+1).eq(Face::getFid,face.getFid()).update();faceResult.setMsg(face.getFaceName()+",当前人脸被禁用");faceResult.setName(face.getFaceName());faceResult.setCode(FaceResult.FORBIDDEN_FACE);faceState = faceResult;// 就算上一张人脸被禁用还得往下执行// 可能当前用户存在多张人脸,if (faceLength == 1){return faceResult;}faceLength --;}}else {// 人脸库没有检测到人脸if (faceLength == 1){// 判断当前人脸是否被禁用,如被禁用,提示被禁用// 禁用优先级大于 没有检测到人脸return faceState != null?faceState:FaceResult.error(FaceResult.NOT_FOUND_FACE,"人脸库不存在该人脸",faceResult.getScore());}faceLength --;}}else {// 接口返回异常return faceResult;}}}// 空异常return FaceResult.error(FaceResult.NULL_ERROR,"空指针异常");}public FaceResult initFace(String imageBase){FaceResult faceResult = new FaceResult();Face face = new Face();face.setFaceBase(imageBase);face.setCreateTime(new Date());face.setVefNum(0);face.setFaceName("admin");face.setFaceStatus(0);boolean save = save(face);faceResult.setCode(FaceResult.INIT_FACE);faceResult.setMsg("人脸初始化"+(save?"成功":"失败")+","+(save?"请验证登录":"请稍后再试"));faceResult.setName(face.getFaceName());return faceResult;}
}

5,前端代码

/*** 获取 浏览器 拍照的权限*/
/*** 获取浏览器权限* @param option*/
function getCamera(option) {option.thisCancas = document.getElementById(option.canvasId);option.thisContext = option.thisCancas.getContext("2d");option.thisVideo = document.getElementById(option.videoId);option.thisVideo.style.display = "block";// 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象if (navigator.mediaDevices === undefined) {navigator.mediaDevices = {};}// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象// 使用getUserMedia,因为它会覆盖现有的属性。// 这里,如果缺少getUserMedia属性,就添加它。if (navigator.mediaDevices.getUserMedia === undefined) {navigator.mediaDevices.getUserMedia = function (constraints) {// 首先获取现存的getUserMedia(如果存在)var getUserMedia =navigator.webkitGetUserMedia ||navigator.mozGetUserMedia ||navigator.getUserMedia;// 有些浏览器不支持,会返回错误信息// 保持接口一致if (!getUserMedia) {//不存在则报错return Promise.reject(new Error("getUserMedia is not implemented in this browser"));}// 否则,使用Promise将调用包装到旧的navigator.getUserMediareturn new Promise(function (resolve, reject) {getUserMedia.call(navigator, constraints, resolve, reject);});};}var constraints = {audio: false,video: {width: option.videoWidth,height: option.videoHeight,transform: "scaleX(-1)",},};navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {// 旧的浏览器可能没有srcObjectif ("srcObject" in option.thisVideo) {option.thisVideo.srcObject = stream;} else {// 避免在新的浏览器中使用它,因为它正在被弃用。option.thisVideo.src = window.URL.createObjectURL(stream);}option.thisVideo.onloadedmetadata = function (e) {option.thisVideo.play();};}).catch((err) => {console.log(err);});return option
}/*** 绘制图片* 返回格式为base64* @param option*/
function draw(option){option.thisContext.drawImage(option.thisVideo,0,0,option.videoWidth,option.videoHeight);return option.thisCancas.toDataURL("image/png");
}export default {getCamera,draw
}
<template><div><div class="login"></div><!--登录中间块--><div class="login-mid"><div class="login-mid-top"><div class="shadow-top-left"></div><div class="shadow-top-right"></div></div><div class="login-mid-mid"><!--捕获人脸区域--><div class="videoCamera-canvasCamera"><videoid="videoCamera":width="videoWidth":height="videoHeight"autoplay></video><canvasstyle="display: none"id="canvasCamera":width="videoWidth":height="videoHeight"></canvas><!--人脸特效区域--><div v-if="faceImgState" class="face-special-effects-2"></div><div v-else class="face-special-effects"></div></div><!--按钮区域--><div class="face-btn"><button @click="faceVef()">{{faceImgState?'正在识别中...':'开始识别'}}</button></div><!--消息区域--><div class="msg"><div class="server-msg">{{msg}}</div><div class="welcome">Welcome to face recognition</div></div></div><div class="login-mid-bot"><div class="shadow-bot-left"></div><div class="shadow-bot-right"></div></div></div></div></template>
<script>
import $camera from '../../camera/index.js'
export default {data() {return {videoWidth: 200,videoHeight: 200,msg:'',faceImgState:false,faceOption:{}};},mounted() {//调用摄像头this.faceOption = $camera.getCamera({videoWidth: 200,videoHeight: 200,thisCancas: null,thisContext: null,thisVideo: null,canvasId:'canvasCamera',videoId:'videoCamera'});//this.getCompetence();},methods: {// 调用后台接口faceVef(){// 开始绘制图片let imageBase = $camera.draw(this.faceOption)if (this.faceImgState){return}this.faceImgState = trueif (imageBase === '' || imageBase === null || imageBase === undefined){this.$message.error("图片数据为空")}else {this.$http.post("/face/vef",{imageBase}).then(res =>{console.log(res)this.faceImgState = false// 跳转首页if (res.data.code === 200){// 关闭摄像头this.faceOption.thisVideo.srcObject.getTracks()[0].stop();localStorage.setItem("face_token",res.data.token);localStorage.setItem("username",res.data.name);this.$message.success(res.data.msg)this.$router.push("/home")}if (res.data.code === 201){this.$message.success(res.data.msg)}},onerror =>{this.faceImgState = false})}}},
};
</script>
<style>
@import "./index.css";
</style>

6,实现实例

参考:项目后端地址face-easy
参考:项目前端地址face-ui

相关文章:

web人脸登录

1&#xff0c;需要腾讯人脸第三方 腾讯人脸第三方申请步骤 2&#xff0c;相关表结构设计 create database faceDB;use faceDB; -- 人脸表 create table face( fid int primary key auto_increment COMMENT 主键, face_base longtext COMMENT 图片数据 base_64编码, create_tim…...

C++数字

目录 一、什么是数字 二、定义数字 三、数学运算 四、随机数 一、什么是数字 通常&#xff0c;当我们需要用到数字时&#xff0c;我们会使用原始的数据类型&#xff0c;如 int、short、long、float 和 double 等等。这些用于数字的数据类型&#xff0c;其可能的值和数值范围…...

【python】用plotly绘制正二十面体

文章目录顶点棱实现正二十面体plotly 的 Python 软件包是一个开源的代码库&#xff0c;它基于 plot.js&#xff0c;而后者基于 d3.js。我们实际使用的则是一个对 plotly 进行封装的库&#xff0c;名叫 cufflinks&#xff0c;能让你更方便地使用 plotly 和 Pandas 数据表协同工作…...

[Datawhale][CS224W]图机器学习(五)

这里写目录标题一、Deepwalk1.1 预备知识1.2 Deepwalk介绍1.3 Embedding1.4 word2Vec 词向量&#xff0c;词嵌入1.5 random Walk随机游走1.6 DeepWalk 核心代码Random WalkWord2vecDeepWalk应用1.7 DeepWalk优缺点二、Node2Vec2.1 图嵌入2.2 Node2Vec优化目标顶点序列采样策略2…...

Windows部署Jar包的三种方式

文章目录1、cmd命令启动2、bat脚本启动2.1 启动jar包2.2 关闭服务3、使用WinSW3.1 重命名3.2 xml配置3.3 安装服务3.4 卸载服务3.5 启动和停止服务1、cmd命令启动 这种方式比较简单&#xff0c;但是窗口关闭后服务也就被杀死了&#xff0c;命令如下 java -jar xxx.jar2、bat脚…...

【图像分类】卷积神经网络之AlexNet网络模型结构详解

写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 1. 前言 LeNet5网络模型提出之后,卷积神经网络在很长一段时间都没有长足的发展,主要有以下两个原因: 1.1 训…...

学习动漫插画的网络班排行榜

很多小伙伴不知道动漫插画培训机构哪个好&#xff0c;找不到靠谱的插画班&#xff0c;今天给大家整理了国内动漫插画培训机构排名&#xff01; 一&#xff1a;动漫插画培训机构排名 1、轻微课&#xff08;五颗星&#xff09; 主打课程有日系插画、游戏原画、古风插画、动漫漫画…...

SpringCloud第五讲 Nacos注册中心-服务注册到Nacos

1.引入依赖&#xff1a; 在父工程中添加spring-cloud-alibaba的管理依赖 <!-- Nacos的管理依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version…...

IP地理位置定位技术原理是什么

IP地理位置定位技术的原理是基于IP地址的网络通信原理和基础上的。它利用IP地址所包含的一些信息&#xff0c;如网络前缀和地址段&#xff0c;以及ISP的IP地址归属地数据库&#xff0c;来推测IP地址所对应的地理位置。具体来说&#xff0c;IP地址是由32位二进制数字组成的&…...

j-vxe-table 下拉搜索选择框数据加载过多导致前端崩溃问题

Jeeg-boot j-vxe-table 下拉搜索选择框数据加载过多导致前端崩溃问题 最近用到了Jeeg-boot j-vxe-table的组件&#xff0c;这组件时真J8难用&#xff0c;还好多BUG&#xff0c;想用个slot插槽也用不了&#xff0c;好像官方写了个基础就没怎么管了。&#x1f611; 问题&#xf…...

Java国际化ResourceBundle详解

在Java开发中&#xff0c;ResourceBundle是一种方便地管理本地化资源的机制。它可以使得程序能够根据当前系统环境的语言和国家/地区来自动加载相应的本地化资源文件&#xff0c;从而避免了硬编码和减少了重复的代码。以下是使用ResourceBundle的基本步骤&#xff1a; 1. 准备…...

一文高端Android性能优化-总结篇

以下从几个方面来总结一下Android的性能优化&#xff1a;1&#xff1a;界面卡顿优化2&#xff1a;内存优化3&#xff1a;App启动优化界面卡顿优化Android的界面为每秒60帧&#xff0c;即必须在16ms内完成1帧的绘制&#xff0c;如果某个方法耗时过程&#xff0c;导致16ms内无法完…...

深入讲解CFS组调度!(上)

注&#xff1a;本文缩写说明 一、CFS组调度简介 1.1. 存在的原因 总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢&#xff0c;比如多用户计算机系统每个用户的所有任务划分到一个分组中&#xff0c;A用户90个相同任务&#xff0c;而B…...

大数据实操项目分享:餐饮智能推荐服务在线实习项目

项目背景&#xff1a;在“互联网"背景下&#xff0c;餐饮企业的经营方式发生了很大的变革&#xff1a;团购和020拓宽了销售 渠道&#xff0c;电子点餐、店内WIFI等信息技术提升了服务水平&#xff0c;大数据、私人定制更好地满足了细分市场的需求等。但是与此同时&#xf…...

代码随想录day38

动态规划五部曲 确定dp数组以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 509. 斐波那契数 https://leetcode.cn/problems/fibonacci-number/ class Solution {public int fib(int n) {if(n0) return 0;if(n<3) return 1;int[] dp new int[n]…...

《计算机网络:自顶向下方法》实验5:TCP

Q1 包含HTTP POST消息的TCP报文段的序号是多少?注意:为了发现POST 命令, 你需要在wireshark底部的报文内容域窗口中去查找,查找数据中包含 “POST”的段。 如图所示,由报文中的POST 和 HTTP/1.1可知,其包含HTTP POST消息; TCP报文段的序号可见TCP报文: Sequence Number:…...

【踩坑指南】Stable Diffusion 服务器端部署笔记

文章目录下载github文件配置环境ckpt文件权重下载生成图像NSFW检查&#xff08;瑟图过滤&#xff09;下载github文件 https://github.com/CompVis/stable-diffusion 这个网址&#xff0c;下载压缩包解压&#xff0c;也可以用git clone下载 配置环境 这一步坑最多&#xff0c…...

[qiankun]-多页签缓存

[qiankun]-多页签缓存环境功能需求多页签缓存方案方案1.主服务进行html替换方案2.微服务vnode 替换方案3.每个微服务都不卸载微服务加载方式的选择微服务的路由路径选择微服务的缓存工具微服务的容器使用tab作为微服务的挂载容器使用微服务路由作为微服务的挂载容器场景描述微服…...

2|电子技术|数字电子技术基础|雨课堂习题|考前回顾

A/DD/A转化横向与阵列 相乘&#xff0c;竖向为或阵列 相加&#xff01;功率放大电路克服交越失真&#xff0c;是在乙类的基础上增加两个二极管&#xff0c;使微导通&#xff0c;使三极管导通时间大于半个周期&#xff0c;小于一个周期&#xff0c;构成甲乙类工作状态。选择填空…...

vue+echarts:圆形柱状图设置角度和最大值

第020个点击查看专栏目录本示例是显示圆形的柱状图&#xff0c;angleAxis设置一个max&#xff0c; angleAxis上startAngle&#xff1a;90 &#xff0c; 将0点设置为最顶点。 文章目录示例效果示例源代码&#xff08;共100行&#xff09;相关资料参考专栏介绍示例效果 示例源代码…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...