人脸考勤签到进阶篇
目錄
簽到業務流程說明
一、需求介紹
二、如何獲取地理信息?
三、如何判定某地區新冠疫情的風險等級?
開通騰訊位置服務
二、騰訊位置服務SDK
把定位坐標轉換成真實地址
一、獲取定位坐標
二、編輯簽到頁面
在Docker中安裝人臉識別鏡像
安裝Docker程序
導入人臉識別鏡像
運行人臉識別程序
一、創建Docker容器
二、運行人臉識別程序
三、接口調用
實現人臉簽到(持久層)?
一、維護員工人臉模型數據
二、保存簽到記錄
實現人臉簽到(業務層)
一、判斷簽到用戶是否存在人臉模型
查詢簽到所在地區新冠疫情風險等級
一、利用本地寶查詢地區風險等級
二、編寫持久層代碼
三、補充簽到業務層代碼
發送疫情高風險地區告警郵件
一、為什么要采用異步發送郵件?
二、導入Email郵件庫
三、設置SMTP服務器信息
二、實現異步發送郵件
實現人臉簽到(Web層)
一、設置上傳圖片存儲的路徑
二、編輯Controller類?
創建新員工人臉模型數據(業務層)?
一、編寫抽象方法
二、編寫創建人臉模型方法
創建新員工人臉模型數據(Web層)
實現人臉簽到(移動端)
簽到業務流程說明
一、需求介紹
????????Emos系統的人臉簽到模塊包含的功能非常豐富,不僅僅只有人臉識別的簽到功能,而且還可以根據用戶簽到時候的地理定位,計算出該地區是?新冠疫情?的?高風險?還是?低風險?地區。如果員工是在疫情高風險地區簽到的,Emos系統會立即向公司人事部門發送告警郵件。
二、如何獲取地理信息?
????????微信小程序提供了獲取地理定位的接口方法,我們調用該方法就能獲取到地理坐標。但是我們得到的僅僅是坐標而已,我們還需要把地理坐標轉換成地址信息,例如什么省份、什么城市、什么街道等等。
????????騰訊位置服務提供了把地理坐標轉換成地址這個功能,只需要我們注冊之后就可以免費使用了。并且還提供了JS調用接口,我們在小程序中可以很簡單的把地理坐標轉換成地址信息。
三、如何判定某地區新冠疫情的風險等級?
????????本地寶這個網站提供了新冠疫情地區風險等級的查詢,我們輸入自己的地址,就能看到具體的風險等級。
????????既然我們已經把地理坐標轉換成了地址信息,那么就可以根據地址信息去查詢風險等級了。但是本地寶并沒有提供Web接口讓我們調用,所以我們只能URL地址傳參的方式獲取本地寶返回的響應。而且響應的內容是HTML,我們還要從HTML中解析出我們想要的風險等級信息。
開通騰訊位置服務
一、開通騰訊位置服務步驟
????????因為Emos簽到流程中要獲取用戶當前所在地址的信息,所以需要把定位坐標緩存成地址,恰好騰訊位置服務提供了這個功能。所以我們按照提示開通這個服務即可,該服務對開發者來說是免費的,所以我們可以放心使用。?
????????首先我們用瀏覽器訪問 騰訊位置服務 官網,然后在頁面的右上角點擊注冊按鈕,并且填寫注冊信息。?
????????在 應用管理 ?〉我的應用 欄目中,可以看到已經創建的密鑰。如果是新注冊的用戶,這里沒有任何密鑰,需要你自己創建一個新的密鑰。
????????根據提示填寫密鑰的信息。密鑰創建成功之后,你要把密鑰字符串記錄下來,在小程序開發當中會用到。
????????把該密鑰和咱們的小程序關聯在一起,在界面中填寫小程序的授權ID。
二、騰訊位置服務SDK
????????騰訊位置服務提供了多種SDK程序包,其中的JavaScript版本的SDK適用于微信小程序,所以我們下載這個SDK包。?
????????登陸微信公眾平臺里面,在“開發管理” -> “開發設置”中設置request合法域名,添加https://apis.map.qq.com 。
????????在小程序項目中,創建?lib?目錄,把SDK文件放入其中。
把定位坐標轉換成真實地址
一、獲取定位坐標
可以通過用戶授權API來判斷用戶是否給應用授予定位權限。
uni.authorize(OBJECT)
uni.authorize({scope: 'scope.userLocation',success() {uni.getLocation()} })注意:scope.userLocation 權限需要在 manifest.json 配置 permission?
????????微信小程序提供了定位接口,只需要我們調用方法即可。uni-app框架的uni對象里面也封裝了地理定位的方法,我們來看一下。
uni.getLocation(OBJECT)? ? ?
????????獲取當前的地理位置和速度。 在微信小程序中,當用戶離開應用后,此接口無法調用,除非申請后臺持續定位權限;當用戶點擊“顯示在聊天頂部”時,此接口可繼續調用。?
// 示例 uni.getLocation({type: 'wgs84',success: function (res) {console.log('當前位置的經度:' + res.longitude);console.log('當前位置的緯度:' + res.latitude);} });二、編輯簽到頁面
我們首先要獲取用戶簽到時的地理定位
uni.showLoading({title: '簽到中請稍后' 3. });setTimeout(function() { 5. uni.hideLoading(); }, 30000); //獲取地理定位 uni.getLocation({type: 'wgs84',success: function(resp) {let latitude = resp.latitude;let longitude = resp.longitude;} })接下來我們根據定位坐標,換算成真實地址,先引用騰訊位置SDK文件?
var QQMapWX = require('../../lib/qqmap-wx-jssdk.min.js'); var qqmapsdk;?然后在?onLoad()?生命周期函數中,初始化?qqmapsdk?對象?
onLoad: function() {?qqmapsdk = new QQMapWX({key: 'KSFBZ-####-####-####-37KUE-W3FLZ'}); },編寫JS代碼把GPS坐標轉換成地址?
qqmapsdk.reverseGeocoder({location: {?latitude: latitude,?longitude: longitude},success: function(resp) {?// console.log(resp.result);let address = resp.result.address;?let addressComponent = resp.result.address_component;let nation = addressComponent.nation;let province = addressComponent.province;let city = addressComponent.city;let district = addressComponent.district;} })在Docker中安裝人臉識別鏡像
安裝Docker程序
執行下面的指令,稍等片刻,Docker程序就安裝好了?
yum install docker -y?管理Docker程序的命令也非常簡單,如下:
service docker startservice docker stopservice docker restart導入人臉識別鏡像
把?face.tar.gz?文件上傳到CentOS系統?
把鏡像導入Docker環境
#導入鏡像文件docker load < face.tar.gz#查看安裝的鏡像docker images#刪除鏡像docker rmi face運行人臉識別程序
一、創建Docker容器
????????上節課我們在Docker中安裝了人臉識別鏡像,因為人臉識別程序是用Python寫的,而且需要很多依賴庫,安裝起來非常麻煩,所以我就把依賴環境和人臉識別程序封裝成Docker鏡像,只要你在本地Docker上面導入鏡像,創建出容器,就能運行Python人臉程序了。?
把?demo.tar?文件上傳到Linux根目錄,然后解壓縮?
tar -xvf demo.tar????????解壓縮之后,demo文件夾中就包含了人臉識別Python程序,我們只需要把demo文件夾掛載到Docker容器,那么在容器中就能訪問Linux主機的demo文件夾了。下面開始創建容器,映射端口號,掛載目錄。?
#創建容器,把容器3000端口映射到宿主機3000端口,把/demo映射到宿主機的/demodocker run -d -it -p 3000:3000 -v /demo:/demo --name node face#查看容器運行狀態docker ps -a?#進入到node容器docker exec -it node bash二、運行人臉識別程序
進入到node容器之后,然后進入?/demo?目錄,運行人臉識別程序
cd /demo#把Python程序掛起到后臺運行nohup python3 -c "from app import app;" > log.out 2>&1 &ps -auxkill -9 進程ID三、接口調用
人臉識別程序程序結合了Flask框架,提供Web接口,具體如下?
1.?創建人臉模型數據?
????????當Emos系統的MySQL數據庫中不存在簽到員工的人臉模型數據,這時候應該調用人臉識別程序的Web接口,上傳照片文件,然后由Python程序識別照片中的人臉,返回人臉模型數據。Java系統接收到人臉模型數據之后,把數據保存在MySQL數據表里面。?
接口名稱:/create_face_model?
請求類型:POST?
傳入參數:icode
返回結果:人臉模型數據?
2.?執行人臉簽到識別?
接口名稱:/checkin?
請求類型:POST?
傳入參數:icode?
返回結果:人臉識別結果
實現人臉簽到(持久層)?
一、維護員工人臉模型數據
在?TbFaceModelDao.xml?文件中添加SQL語句?
<select id="searchFaceModel" parameterType="int" resultType="String">SELECT face_model FROM tb_face_modelWHERE user_id=#{userId}</select><insert id="insert" parameterType="com.example.emos.wx.db.pojo.TbFaceModel">INSERT INTO tb_face_modelSET user_id=#{userId},face_model=#{faceModel}</insert><delete id="deleteFaceModel" parameterType="int">DELETE FROM tb_face_modelWHERE user_id=#{userId}</delete>在?TbFaceModelDao.java?接口中添加DAO方法??
@Mapper public interface TbFaceModelDao {public String searchFaceModel(int userId);public void insert(TbFaceModel faceModel);public int deleteFaceModel(int userId); }二、保存簽到記錄
在?TbCheckinDao.xml?文件中添加INSERT語句
<insert id="insert" parameterType="com.example.emos.wx.db.pojo.TbCheckin">INSERT INTO tb_checkinSET user_id=#{userId},<if test="address!=null">address=#{address},</if><if test="country!=null">country=#{country},</if><if test="province!=null">province=#{province},</if><if test="city!=null">city=#{city},</if><if test="district!=null">district=#{district},</if>status=#{status},<if test="risk!=null">risk=#{risk},</if>date=#{date},create_time=#{createTime}</insert>在?TbCheckinDao.java?中添加抽象方法?
@Mapper public interface TbCheckinDao {……public void insert(TbCheckin entity); }實現人臉簽到(業務層)
一、判斷簽到用戶是否存在人臉模型
在?application.yml?文件中,添加值注入信息?
emos:……face:createFaceModelUrl: http://CentOS的IP地址:3000/create_face_modelcheckinUrl: http://CentOS的IP地址:3000/checkincode: HelloWorld創建?CheckinForm.java?表單類,接收小程序提交的簽到數據?
@Data @ApiModel public class CheckinForm {private String address;private String country;private String province;private String city;private String district; }在?CheckinService.java?接口中添加抽象的簽到方法?
public interface CheckinService {……public void checkin(HashMap param); }在?CheckinServiceImpl.java?中實現抽象方法
@Service @Scope("prototype") @Slf4j public class CheckinServiceImpl implements CheckinService {@Autowiredprivate TbFaceModelDao faceModelDao;@Value("${emos.face.checkinUrl}")private String checkinUrl;@Autowiredprivate SystemConstants constants;@Value("${emos.code}")private String code;@Overridepublic void checkin(HashMap param) {Date d1=DateUtil.date();Date d2=DateUtil.parse(DateUtil.today()+" "+constants.attendanceTime);Date d3=DateUtil.parse(DateUtil.today()+" "+constants.attendanceEndTime);int status=1;if(d1.compareTo(d2)<=0){status=1;}else if(d1.compareTo(d2)>0&&d1.compareTo(d3)<0){status=2;}else{throw new EmosException("超出考勤時間段,無法考勤");}int userId= (Integer) param.get("userId");String faceModel=faceModelDao.searchFaceModel(userId);if(faceModel==null){throw new EmosException("不存在人臉模型");}else{String path=(String)param.get("path");HttpRequest request= HttpUtil.createPost(checkinUrl);request.form("photo", FileUtil.file(path),"targetModel",faceModel);request.form("code",code);HttpResponse response=request.execute();if(response.getStatus()!=200){log.error("人臉識別服務異常");throw new EmosException("人臉識別服務異常");}String body=response.body();if("無法識別出人臉".equals(body)||"照片中存在多張人臉".equals(body)){throw new EmosException(body);}else if("False".equals(body)){throw new EmosException("簽到無效,非本人簽到");}else if("True".equals(body)){//TODO 查詢疫情風險等級//TODO 保存簽到記錄}}} }查詢簽到所在地區新冠疫情風險等級
@Data public class TbCheckin implements Serializable {private String date;private Date createTime; }延伸:date字段是日期類型,createTime字段是Datetime類型。Java中沒有Datetime類型,所以映射時用了日期類型-Date類。數據表中date類型就是date類型,保存的數據就是日期不包含時間。如果映射成Java中的日期類型,Java中日期類型還會有小時分鐘秒毫秒,這些信息不應該存在。所以一個正確的ORM映射,就是把數據表中date類型字段映射到Java的string變量上。這樣就只保存了日期數據,并不包含小時分鐘秒毫秒之類的。
一、利用本地寶查詢地區風險等級
????????本地寶H5網頁提供了新冠疫情風險等級查詢,在網頁上面直接輸入地區,就能查詢到疫情的風險等級。?
????????Java程序想要查詢用戶簽到地區的風險等級,不能到頁面里面點來點去的,所以我們要用URL傳參的方式,把地址信息傳入本地寶的H5頁面。?
????????你可以在瀏覽器地址欄填寫下方的URL連接,就能查詢到北京市西城區當前的新冠疫情風險等級。
????????http://m.bj.bendibao.com/news/yqdengji/?qu=西城區
從上面的案例推斷,URL地址要傳入兩個參數:?城市編碼?和?區縣?。?
城市編碼可以從?tb_city?表中查詢到,其中的code字段就是城市對應的編號。
????????我們可以用小程序提交過來的簽到城市,然后到?tb_city?表中根據城市名稱查詢到城市編號。接下來,就可以把參數添加到URL上面。?
????????我們想要提取查詢到的風險等級結果應該怎么辦呢?這個很簡單,用Java程序解析本地寶HTML頁面的標簽,提取我們想要的結果信息即可。在Java領域中?jsoup?提供了解析HTML標簽的功能,所以我們要在Java項目中引入?jsoup?庫。?
在?pom.xml?文件中添加?jsoup?依賴,然后重新reload項目
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.13.1</version> </dependency>二、編寫持久層代碼
在?TbCityDao.xml?文件中添加查詢語句?
<select id="searchCode" parameterType="String" resultType="String">?SELECT codeFROM tb_cityWHERE city = #{city} </select>在?TbCityDao.java?接口中添加抽象方法?
@Mapper public interface TbCityDao {?public String searchCode(String city); }三、補充簽到業務層代碼
在?CheckinServiceImpl.java?文件中繼續補充查詢疫情風險等級的代碼?
@Autowired private TbCityDao cityDao;@Override public void checkin(HashMap param) {……String faceModel=faceModelDao.searchFaceModel(userId);if(faceModel==null){throw new EmosException("不存在人臉模型");}else{……if("無法識別出人臉".equals(body)||"照片中存在多張人臉".equals(body)){throw new EmosException(body);}else if("False".equals(body)){throw new EmosException("簽到無效,非本人簽到");}else if("True".equals(body)){//查詢疫情風險等級int risk=1;String city= (String) param.get("city");String district= (String) param.get("district");String address= (String) param.get("address");String country= (String) param.get("country");String province= (String) param.get("province");if(!StrUtil.isBlank(city)&&!StrUtil.isBlank(district)){String code=cityDao.searchCode(city);try{String url = "http://m." + code + ".bendibao.com/news/yqdengji/?qu=" + district;Document document=Jsoup.connect(url).get();Elements elements=document.getElementsByClass("list-content");if(elements.size()>0){Element element=elements.get(0);String result=element.select("p:last-child").text();// result="高風險";if("高風險".equals(result)){risk=3;//發送告警郵件}else if("中風險".equals(result)){risk=2;}}}catch (Exception e){log.error("執行異常",e);throw new EmosException("獲取風險等級失敗");}}//保存簽到記錄TbCheckin entity=new TbCheckin();entity.setUserId(userId);entity.setAddress(address);entity.setCountry(country);entity.setProvince(province);entity.setCity(city);entity.setDistrict(district);entity.setStatus((byte) status);entity.setRisk(risk);entity.setDate(DateUtil.today());entity.setCreateTime(d1);checkinDao.insert(entity);}}} }發送疫情高風險地區告警郵件
一、為什么要采用異步發送郵件?
????????因為在簽到過程中,執行人臉識別和查詢疫情風險等級,都比較消耗時間。如果發送郵件再做成同步執行的,勢必導致簽到執行時間過長,影響用戶體驗。由于要把簽到結果保存到簽到表,所以人臉識別和疫情風險等級查詢必須是同步執行的。發送郵件跟保存簽到數據沒有直接關聯,所以做成異步并行執行的程序更好一些,這樣也能縮短用戶簽到時候等待的時間。
二、導入Email郵件庫
編輯?pom.xml?文件,添加依賴庫?
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency>三、設置SMTP服務器信息
????????發送郵件是通過SMTP服務器來完成的,所以我們要配置一下SMTP服務器的連接信息。這里我以163的SMTP服務器為例,并且提前已經開啟了163郵箱的SMTP功能。?
spring:……mail:default-encoding: UTF-8host: smtp.163.comusername: *************@163.compassword: 此處是密碼????????接下來我們把系統內的常用郵箱聲明一下,以后會用到這些郵箱往外發送郵件,或者給這些郵箱發送內部郵件。例如,員工簽到地點是疫情高風險地區,那么就應該向HR郵箱發送郵件,告知人事總監有員工需要隔離。?
emos:……email:system: *********@163.comhr: **********@qq.com二、實現異步發送郵件
在SpringBoot項目中開啟異步多線程非常簡單,只需要下面幾個步驟即可。?
在主類上面開啟?@EnableAsync?注解?
…… @EnableAsync public class EmosWxApiApplication {?…… }?在?com.example.emos.wx.config?中創建?ThreadPoolConfig?類,聲明Java線程池?
@Configuration public class ThreadPoolConfig {@Bean("AsyncTaskExecutor")public AsyncTaskExecutor taskExecutor(){ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();// 設置核心線程數executor.setCorePoolSize(8);// 設置最大線程數executor.setMaxPoolSize(16);// 設置隊列容量executor.setQueueCapacity(32);// 設置線程活躍時間(秒)executor.setKeepAliveSeconds(60);// 設置默認線程名稱executor.setThreadNamePrefix("task-");// 設置拒絕策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;} }// 線程池對象自動注冊給Spring項目了。在?com.example.emos.wx.task?中創建?EmailTask?類,定義線程任務
@Component @Scope("prototype") public class EmailTask implements Serializable {@Autowiredprivate JavaMailSender javaMailSender;@Value("${emos.email.system}")private String mailbox;@Asyncpublic void sendAsync(SimpleMailMessage message){message.setFrom(mailbox);// message.setCc(mailbox); // 抄送給自己javaMailSender.send(message);} }// @Component // @Scope("prototype") // Serializable // @Async // 都是必須的查詢員工的姓名和部門名稱,在?TbUserDao.xml?文件中聲明查詢語句?
<select id="searchNameAndDept" parameterType="int" resultType="HashMap">?SELECT u.name, d.dept_nameFROM tb_user u LEFT JOIN tb_dept d ON u.dept_id=d.idWHERE u.id = #{userId} AND u.status = 1 </select>在?TbUserDao?接口中定義抽象方法?
public HashMap searchNameAndDept(int userId);定義值注入變量,用來接收人員隔離告警郵件?
@Value("${emos.email.hr}")? private String hrEmail;?@Autowired private EmailTask emailTask;?@Autowired private TbUserDao userDao;編寫發送告警郵件的代碼?
HashMap<String,String> map=userDao.searchNameAndDept(userId); String name = map.get("name"); String deptName = map.get("dept_name"); deptName = deptName != null ? deptName : ""; SimpleMailMessage message=new SimpleMailMessage(); message.setTo(hrEmail); message.setSubject("員工" + name + "身處高風險疫情地區警告"); message.setText(deptName + "員工" + name + "," + DateUtil.format(new Date(), "yyyy年MM月dd日") + "處于" + address + ",屬于新冠疫情高風險地區,請及時與該員工聯系,核實情況!"); emailTask.sendAsync(message);實現人臉簽到(Web層)
一、設置上傳圖片存儲的路徑
????????因為簽到自拍照是臨時使用,所以不需要存儲在騰訊云對象存儲中,我們只需要在本地找個文件夾存放這些簽到照片,簽到業務執行完,就立即刪除該文件即可。?
在?application.yml?文件中,設置圖片存放路徑
emos:……image-folder: D:/emos/image在主類中添加初始化代碼,項目啟動時候自動創建圖片文件夾?
…… public class EmosWxApiApplication {?……@Value("${emos.image-folder}")?private String imageFolder;?……@PostConstructpublic void init(){……new File(imageFolder).mkdirs();}}二、編輯Controller類?
編輯?CheckinController.java?類,定義?checkin()?方法
@RequestMapping("/checkin") @RestController @Api("簽到模塊Web接口") @Slf4j public class CheckinController {@Value("${emos.image-folder}")private String imageFolder;@PostMapping("/checkin")@ApiOperation("簽到")public R checkin(@Valid CheckinForm form,@RequestParam("photo") MultipartFile file,@RequestHeader("token") String token){if(file==null){return R.error("沒有上傳文件");}int userId=jwtUtil.getUserId(token);String fileName=file.getOriginalFilename().toLowerCase();if(!fileName.endsWith(".jpg")){return R.error("必須提交JPG格式圖片");}else{String path=imageFolder+"/"+fileName;try{file.transferTo(Paths.get(path));HashMap param=new HashMap();param.put("userId",userId);param.put("path",path);param.put("city",form.getCity());param.put("district",form.getDistrict());param.put("address",form.getAddress());param.put("country",form.getCountry());param.put("province",form.getProvince());checkinService.checkin(param);return R.ok("簽到成功");}catch (IOException e){log.error(e.getMessage(),e);throw new EmosException("圖片保存錯誤");}finally {FileUtil.del(path);}}} } // 防止照片重名,加上時間戳 if (file != null) {//獲取上傳文件名fileName = file1.getOriginalFilename();//獲取后綴名String sname = fileName.substring(fileName.lastIndexOf("."));//時間格式化格式SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyyMMddHHmmssSSS");//獲取當前時間并作為時間戳String timeStamp=simpleDateFormat.format(new Date());//拼接新的文件名String newName ="人臉識別"+timeStamp+sname;//指定上傳文件的路徑String path = "F:\\" + newName;//上傳保存file.transferTo(new File(path));//保存當前文件路徑request.getSession().setAttribute("currFilePath", path); }創建新員工人臉模型數據(業務層)?
一、編寫抽象方法
????????如果用戶是第一次簽到,checkin方法檢測到數據庫中沒有該員工的人臉模型數據,移動端會收到異常消息,所以要重新發送HTTP請求,讓后端項目用簽到照片創建人臉模型數據。所以我們先來把創建人臉模型的業務層抽象方法聲明一下。?
在?CheckinService?接口中,聲明抽象方法?
public interface CheckinService {……public void createFaceModel(int userId, String path); }二、編寫創建人臉模型方法
在?CheckinServiceImpl?類中,實現抽象方法?
…… public class CheckinServiceImpl implements CheckinService {……@Value("${emos.face.createFaceModelUrl}")private String createFaceModelUrl;……@Overridepublic void createFaceModel(int userId, String path) {HttpRequest request=HttpUtil.createPost(createFaceModelUrl);request.form("photo",FileUtil.file(path));request.form("code",code);HttpResponse response=request.execute();String body=response.body();if("無法識別出人臉".equals(body)||"照片中存在多張人臉".equals(body)){throw new EmosException(body);}else{TbFaceModel entity=new TbFaceModel();entity.setUserId(userId);entity.setFaceModel(body);faceModelDao.insert(entity);}} }創建新員工人臉模型數據(Web層)
在?CheckinController?類中創建?createFaceModel()?方法
@RequestMapping("/checkin") @RestController @Api("簽到模塊Web接口") @Slf4j public class CheckinController {……@PostMapping("/createFaceModel")@ApiOperation("創建人臉模型")public R createFaceModel(@RequestParam("photo") MultipartFile file,@RequestHeader("token") String token){if(file==null){return R.error("沒有上傳文件");}int userId=jwtUtil.getUserId(token);String fileName=file.getOriginalFilename().toLowerCase();if(!fileName.endsWith(".jpg")){return R.error("必須提交JPG格式圖片");}else{String path=imageFolder+"/"+fileName;try{file.transferTo(Paths.get(path));checkinService.createFaceModel(userId,path);return R.ok("人臉建模成功");}catch (IOException e){log.error(e.getMessage(),e);throw new EmosException("圖片保存錯誤");}finally {FileUtil.del(path);}}} }實現人臉簽到(移動端)
? ? ? ? 每人每天只可簽到一次,調試時要刪掉數據表數據。
? ? ? ? 163郵箱反垃圾郵件級別提升,會攔截咱們項目發送郵件,推薦使用阿里郵箱個人版。
? ? ? ? application.yml 中修改 spring.mail 和 emos.email 項
總結
- 上一篇: 新宝线上配资 许多个股都能走出独立行情
- 下一篇: Java,Swing 模拟在线考试系统(