基于JAVA的PC、微信互动,查看PC使用时长

8 篇文章 0 订阅
2 篇文章 0 订阅

前段时间被领导警告,离开工位(摸鱼)时间太长。于是做了一个能查看自己离开工位时间的项目。

基本技术栈及设施

云服务器一台:用于提供公网服务,方便手机微信访问
编程技术栈:Spring + Boot + Web + thymeleaf 、HTML 、 MySql +、ORM

一、思路

1、PC机器上需要一个APP,检测PC锁屏、解锁
2、PC锁屏、解锁后储存记录到MySql
3、云服务器部署另一个APP,微信(网页)访问时,输出休息时间
4、将网页添加到微信收藏、并放到左侧快捷栏
5、休息时,打开快捷页面,访问即可查看当前休息时间

二、实现具体步骤

说明: 编程技术栈不再过多阐述,只讲述关键功能方法

1、检测PC锁屏、解锁

pom文件引用包

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.26</version>
      <scope>provided</scope>
    </dependency>
    <!-- jna -->
    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna</artifactId>
      <version>5.12.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna-platform -->
    <dependency>
      <groupId>net.java.dev.jna</groupId>
      <artifactId>jna-platform</artifactId>
      <version>5.12.1</version>
    </dependency>

windows系统锁屏、解锁监听类

package org.dlg.win.system;

import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.DBT.*;
import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.platform.win32.WinUser.HDEVNOTIFY;
import com.sun.jna.platform.win32.WinUser.MSG;
import com.sun.jna.platform.win32.WinUser.WNDCLASSEX;
import com.sun.jna.platform.win32.WinUser.WindowProc;
import lombok.Setter;

/**
 * 监听windows用户状态
 * OnWindowsLockListener 是个人实现的锁定解锁监听接口
 * 需要监听其它状态可以参照实现
 *
 * The Class Win32WindowTest.
 * @author lingui
 */
public class WinState implements WindowProc,Runnable {

    /**
     * 锁定监听
     */
    public interface OnWindowsLockListener{

        /**
         * 锁定
         */
        void onLocked();

        /**
         * 解锁
         */
        void onUnLocked();

    }

    @Setter
    private OnWindowsLockListener listener;

    @Override
    public void run(){
        // define new window class
        String windowClass = "MyWindowClass";
        HMODULE hInst = Kernel32.INSTANCE.GetModuleHandle("");

        WNDCLASSEX wClass = new WNDCLASSEX();
        wClass.hInstance = hInst;
        wClass.lpfnWndProc = WinState.this;
        wClass.lpszClassName = windowClass;

        // register window class
        User32.INSTANCE.RegisterClassEx(wClass);
        getLastError();

        // create new window
        HWND hWnd = User32.INSTANCE
                .CreateWindowEx(
                        User32.WS_EX_TOPMOST,
                        windowClass,
                        "My hidden helper window, used only to catch the windows events",
                        0, 0, 0, 0, 0,
                        null, // WM_DEVICECHANGE contradicts parent=WinUser.HWND_MESSAGE
                        null, hInst, null);

        getLastError();
//        System.out.println("window sucessfully created! window hwnd: "
//                + hWnd.getPointer().toString());

        Wtsapi32.INSTANCE.WTSRegisterSessionNotification(hWnd,
                Wtsapi32.NOTIFY_FOR_THIS_SESSION);

        /* this filters for all device classes */
        // DEV_BROADCAST_HDR notificationFilter = new DEV_BROADCAST_HDR();
        // notificationFilter.dbch_devicetype = DBT.DBT_DEVTYP_DEVICEINTERFACE;

        /* this filters for all usb device classes */
        DEV_BROADCAST_DEVICEINTERFACE notificationFilter = new DEV_BROADCAST_DEVICEINTERFACE();
        notificationFilter.dbcc_size = notificationFilter.size();
        notificationFilter.dbcc_devicetype = DBT.DBT_DEVTYP_DEVICEINTERFACE;
        notificationFilter.dbcc_classguid = DBT.GUID_DEVINTERFACE_USB_DEVICE;

        /*
         * use User32.DEVICE_NOTIFY_ALL_INTERFACE_CLASSES instead of
         * DEVICE_NOTIFY_WINDOW_HANDLE to ignore the dbcc_classguid value
         */
        HDEVNOTIFY hDevNotify = User32.INSTANCE.RegisterDeviceNotification(
                hWnd, notificationFilter, User32.DEVICE_NOTIFY_WINDOW_HANDLE);

        getLastError();
        if (hDevNotify != null) {
            System.out.println("RegisterDeviceNotification was sucessfully!");
        }

        MSG msg = new MSG();
        while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) != 0) {
            User32.INSTANCE.TranslateMessage(msg);
            User32.INSTANCE.DispatchMessage(msg);
        }

        User32.INSTANCE.UnregisterDeviceNotification(hDevNotify);
        Wtsapi32.INSTANCE.WTSUnRegisterSessionNotification(hWnd);
        User32.INSTANCE.UnregisterClass(windowClass, hInst);
        User32.INSTANCE.DestroyWindow(hWnd);

        System.out.println("program exit!");
    }

    /**
     * Instantiates a new win32 window test.
     */
    public WinState() {
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.sun.jna.platform.win32.User32.WindowProc#callback(com.sun.jna.platform
     * .win32.WinDef.HWND, int, com.sun.jna.platform.win32.WinDef.WPARAM,
     * com.sun.jna.platform.win32.WinDef.LPARAM)
     */
    @Override
    public LRESULT callback(HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam) {
        switch (uMsg) {
            case WinUser.WM_CREATE: {
                onCreate(wParam, lParam);
                return new LRESULT(0);
            }
            case WinUser.WM_DESTROY: {
                User32.INSTANCE.PostQuitMessage(0);
                return new LRESULT(0);
            }
            case WinUser.WM_SESSION_CHANGE: {
                this.onSessionChange(wParam, lParam);
                return new LRESULT(0);
            }
            case WinUser.WM_DEVICECHANGE: {
                LRESULT lResult = this.onDeviceChange(wParam, lParam);
                return lResult != null ? lResult :
                        User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);
            }
            default:
                return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
    }

    /**
     * Gets the last error.
     *
     * @return the last error
     */
    public final int getLastError() {
        int rc = Kernel32.INSTANCE.GetLastError();

        if (rc != 0) {
//            System.out.println("error: " + rc);
        }

        return rc;
    }

    /**
     * On session change.
     *
     * @param wParam
     *            the w param
     * @param lParam
     *            the l param
     */
    protected void onSessionChange(WPARAM wParam, LPARAM lParam) {
        switch (wParam.intValue()) {
            case Wtsapi32.WTS_CONSOLE_CONNECT: {
                this.onConsoleConnect(lParam.intValue());
                break;
            }
            case Wtsapi32.WTS_CONSOLE_DISCONNECT: {
                this.onConsoleDisconnect(lParam.intValue());
                break;
            }
            case Wtsapi32.WTS_SESSION_LOGON: {
                this.onMachineLogon(lParam.intValue());
                break;
            }
            case Wtsapi32.WTS_SESSION_LOGOFF: {
                this.onMachineLogoff(lParam.intValue());
                break;
            }
            case Wtsapi32.WTS_SESSION_LOCK: {
                this.onMachineLocked(lParam.intValue());
                break;
            }
            case Wtsapi32.WTS_SESSION_UNLOCK: {
                this.onMachineUnlocked(lParam.intValue());
                break;
            }
            default:
        }
    }

    /**
     * On console connect.
     *
     * @param sessionId
     *            the session id
     */
    protected void onConsoleConnect(int sessionId) {
        System.out.println("onConsoleConnect: " + sessionId);
    }

    /**
     * On console disconnect.
     *
     * @param sessionId
     *            the session id
     */
    protected void onConsoleDisconnect(int sessionId) {
        System.out.println("onConsoleDisconnect: " + sessionId);
    }

    /**
     * On machine locked.
     *
     * @param sessionId
     *            the session id
     */
    protected void onMachineLocked(int sessionId) {
        System.out.println("onMachineLocked: " + sessionId);
        listener.onLocked();
    }

    /**
     * On machine unlocked.
     *
     * @param sessionId
     *            the session id
     */
    protected void onMachineUnlocked(int sessionId) {
        System.out.println("onMachineUnlocked: " + sessionId);
        listener.onUnLocked();
    }

    /**
     * On machine logon.
     *
     * @param sessionId
     *            the session id
     */
    protected void onMachineLogon(int sessionId) {
        System.out.println("onMachineLogon: " + sessionId);
    }

    /**
     * On machine logoff.
     *
     * @param sessionId
     *            the session id
     */
    protected void onMachineLogoff(int sessionId) {
        System.out.println("onMachineLogoff: " + sessionId);
    }

    /**
     * On device change.
     *
     * @param wParam
     *            the w param
     * @param lParam
     *            the l param
     * @return the result. Null if the message is not processed.
     */
    protected LRESULT onDeviceChange(WPARAM wParam, LPARAM lParam) {
        switch (wParam.intValue()) {
            case DBT.DBT_DEVICEARRIVAL: {
                return onDeviceChangeArrival(lParam);
            }
            case DBT.DBT_DEVICEREMOVECOMPLETE: {
                return onDeviceChangeRemoveComplete(lParam);
            }
            case DBT.DBT_DEVNODES_CHANGED: {
                //lParam is 0 for this wParam
                return onDeviceChangeNodesChanged();
            }
            default:
                System.out.println(
                        "Message WM_DEVICECHANGE message received, value unhandled.");
        }
        return null;
    }

    protected LRESULT onDeviceChangeArrivalOrRemoveComplete(LPARAM lParam, String action) {
        DEV_BROADCAST_HDR bhdr = new DEV_BROADCAST_HDR(lParam.longValue());
        switch (bhdr.dbch_devicetype) {
            case DBT.DBT_DEVTYP_DEVICEINTERFACE: {
                // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363244.aspx
                DEV_BROADCAST_DEVICEINTERFACE bdif = new DEV_BROADCAST_DEVICEINTERFACE(bhdr.getPointer());
                System.out.println("BROADCAST_DEVICEINTERFACE: " + action);
                System.out.println("dbcc_devicetype: " + bdif.dbcc_devicetype);
                System.out.println("dbcc_name:       " + bdif.getDbcc_name());
                System.out.println("dbcc_classguid:  " + bdif.dbcc_classguid.toGuidString());
                break;
            }
            case DBT.DBT_DEVTYP_HANDLE: {
                // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363245.aspx
                DEV_BROADCAST_HANDLE bhd = new DEV_BROADCAST_HANDLE(bhdr.getPointer());
                System.out.println("BROADCAST_HANDLE: " + action);
                break;
            }
            case DBT.DBT_DEVTYP_OEM: {
                // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363247.aspx
                DEV_BROADCAST_OEM boem = new DEV_BROADCAST_OEM(bhdr.getPointer());
                System.out.println("BROADCAST_OEM: " + action);
                break;
            }
            case DBT.DBT_DEVTYP_PORT: {
                // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363248.aspx
                DEV_BROADCAST_PORT bpt = new DEV_BROADCAST_PORT(bhdr.getPointer());
                System.out.println("BROADCAST_PORT:  " + action);
                System.out.println("dbcp_devicetype: " + bpt.dbcp_devicetype);
                System.out.println("dbcp_name:       " + bpt.getDbcpName());
                break;
            }
            case DBT.DBT_DEVTYP_VOLUME: {
                // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363249.aspx
                DEV_BROADCAST_VOLUME bvl = new DEV_BROADCAST_VOLUME(bhdr.getPointer());
                int logicalDriveAffected = bvl.dbcv_unitmask;
                short flag = bvl.dbcv_flags;
                boolean isMediaNotPhysical = 0 != (flag & DBT.DBTF_MEDIA/*value is 1*/);
                boolean isNet = 0 != (flag & DBT.DBTF_NET/*value is 2*/);
                System.out.println(action);
                int driveLetterIndex = 0;
                while (logicalDriveAffected != 0) {
                    if (0 != (logicalDriveAffected & 1)) {
                        System.out.println("Logical Drive Letter: " +
                                ((char) ('A' + driveLetterIndex)));
                    }
                    logicalDriveAffected >>>= 1;
                    driveLetterIndex++;
                }
                System.out.println("isMediaNotPhysical:"+isMediaNotPhysical);
                System.out.println("isNet:"+isNet);
                break;
            }
            default:
                return null;
        }
        // return TRUE means processed message for this wParam.
        // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363205.aspx
        // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363208.aspx
        return new LRESULT(1);
    }

    protected LRESULT onDeviceChangeArrival(LPARAM lParam) {
        return onDeviceChangeArrivalOrRemoveComplete(lParam, "Arrival");
    }

    protected LRESULT onDeviceChangeRemoveComplete(LPARAM lParam) {
        return onDeviceChangeArrivalOrRemoveComplete(lParam, "Remove Complete");
    }

    protected LRESULT onDeviceChangeNodesChanged() {
        System.out.println("Message DBT_DEVNODES_CHANGED");
        // return TRUE means processed message for this wParam.
        // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa363211.aspx
        return new LRESULT(1);
    }

    /**
     * On create.
     *
     * @param wParam
     *            the w param
     * @param lParam
     *            the l param
     */
    protected void onCreate(WPARAM wParam, LPARAM lParam) {
//        System.out.println("onCreate: WM_CREATE");
    }

    /**
     * The main method.
     *
     * @param args
     *            the arguments
     */
    @SuppressWarnings("ResultOfObjectAllocationIgnored")
    public static void main(String[] args) {
        WinState winState = new WinState();
        winState.setListener(new OnWindowsLockListener() {
            @Override
            public void onLocked() {
                System.out.println("锁屏了");
            }

            @Override
            public void onUnLocked() {
                System.out.println("解锁");
            }
        });
    }
}

3、编写ServiceApp提供网页

pom文件

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

controller

@Controller
@Slf4j
public class ReleaseHitController {

    @Resource
    TimeHitService timeHitService;
    @Resource
    TbLogService tbLogService;

    @GetMapping("/" + TIME_HIT_PATH)
    public String releaseHit(Model model) {
        ReleaseHitDTO dto = timeHitService.getReleaseTime();
        String stateMsg = "主机当前状态 : " + dto.getState();
        String msg = "距离上次休息时间 : " + dto.getReleaseTime();
        String useMsg = "距离上次解锁时间 : " + dto.getUserTime();
        List<TbLogEntity> list = tbLogService.listLastLog(10);
        List<String> msgList = new ArrayList<>(list.size());
        for (TbLogEntity en:list){
            msgList.add(en.getContent());
        }
        model.addAttribute("msgList", msgList);
        model.addAttribute("useMsg", useMsg);
        model.addAttribute("state", stateMsg);
        model.addAttribute("time", msg);
        return TIME_HIT_PATH;
    }

}

HTML

各位如果觉得写HTML太麻烦,可以使用H5在线页面快速开发,使用拖动等快捷方式做更好看的界面

<!doctype html>
<html lang="ch" xmlns:th="http://www.thymeleaf.org">
<title>休息时间</title>
<body>
<div style="position:fixed;left: 48px">
    <h1 th:text="${state}">主机使用状态</h1>
    <h1 th:text="${time}">距离上次休息</h1>
    <h1 th:text="${useMsg}">距离上次解锁</h1>
    <ul>
        <li th:each="tag:${msgList}" th:text="${tag}"></li>
    </ul>
</div>
<!-- 底部右侧 -->
<div style="position:fixed;bottom:84px;top:auto;right: 48px;">
    <button th:onclick = "'location.reload()'"
        style="width: 240px;height: 120px;font-size: xxx-large">刷新</button>
</div>
</body>

</html>

效果:左侧是浮窗、右侧是休息提醒
在这里插入图片描述

最后:

由于本人最近一年因生活、身体等原因,经常打不起精神,故需要外出放风。
生命的时间有限,摸鱼不可取,建议各位不要学习。
可以把有限的时间投入到写这篇博客、完成类似本篇一样的小项目、或者写日记心得。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*crzep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值