Przeglądaj źródła

数据检查-绑定检查员任务并返回

xiaof 2 lat temu
rodzic
commit
039c44b59e

+ 11 - 0
paper-library-business/src/main/java/com/qmth/paper/library/business/bean/result/PaperLibraryResult.java

@@ -22,6 +22,9 @@ public class PaperLibraryResult extends PaperLibrary implements Serializable {
     @ApiModelProperty(value = "绑定图片数量")
     private int bindCount;
 
+    @ApiModelProperty(value = "图片访问地址")
+    private String fileUrl;
+
     public String getStudentName() {
         return studentName;
     }
@@ -53,4 +56,12 @@ public class PaperLibraryResult extends PaperLibrary implements Serializable {
     public void setBindCount(int bindCount) {
         this.bindCount = bindCount;
     }
+
+    public String getFileUrl() {
+        return fileUrl;
+    }
+
+    public void setFileUrl(String fileUrl) {
+        this.fileUrl = fileUrl;
+    }
 }

+ 7 - 1
paper-library-business/src/main/java/com/qmth/paper/library/business/mapper/PaperLibraryMapper.java

@@ -7,6 +7,8 @@ import com.qmth.paper.library.business.bean.result.PaperLibraryResult;
 import com.qmth.paper.library.business.entity.PaperLibrary;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 /**
  * <p>
  * 图片库 Mapper 接口
@@ -20,5 +22,9 @@ public interface PaperLibraryMapper extends BaseMapper<PaperLibrary> {
 
     IPage<PaperLibraryResult> pageBindData(@Param("page") Page<PaperLibraryResult> page, @Param("paperScanTaskId") Long paperScanTaskId);
 
-    int countBindData(Long paperScanTaskId);
+    int countBindData(@Param("paperScanTaskId") Long paperScanTaskId);
+
+    List<PaperLibrary> listUnBindData(@Param("schoolId") Long schoolId);
+
+    List<PaperLibrary> selectBatchData(@Param("schoolId") Long schoolId, @Param("userId") Long userId);
 }

+ 4 - 0
paper-library-business/src/main/java/com/qmth/paper/library/business/service/PaperLibraryService.java

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.paper.library.business.bean.result.PaperLibraryResult;
 import com.qmth.paper.library.business.entity.PaperLibrary;
 
+import java.util.List;
+
 /**
  * <p>
  * 图片库 服务类
@@ -21,4 +23,6 @@ public interface PaperLibraryService extends IService<PaperLibrary> {
     boolean bind(Long paperLibraryId, Long paperScanTaskDetailId);
 
     int countBindData(Long paperScanTaskId);
+
+    List<PaperLibraryResult> toBindPaper();
 }

+ 49 - 2
paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperLibraryServiceImpl.java

@@ -10,12 +10,18 @@ import com.qmth.paper.library.business.entity.PaperScanTaskDetail;
 import com.qmth.paper.library.business.mapper.PaperLibraryMapper;
 import com.qmth.paper.library.business.service.PaperLibraryService;
 import com.qmth.paper.library.business.service.PaperScanTaskDetailService;
+import com.qmth.paper.library.common.contant.SystemConstant;
 import com.qmth.paper.library.common.entity.SysUser;
 import com.qmth.paper.library.common.enums.ExceptionResultEnum;
+import com.qmth.paper.library.common.lock.LockService;
+import com.qmth.paper.library.common.lock.LockType;
 import com.qmth.paper.library.common.util.ServletUtil;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * <p>
@@ -28,6 +34,9 @@ public class PaperLibraryServiceImpl extends ServiceImpl<PaperLibraryMapper, Pap
     @Resource
     PaperScanTaskDetailService paperScanTaskDetailService;
 
+    @Resource
+    LockService lockService;
+
     @Override
     public IPage<PaperLibraryResult> pageUnbindData(Long paperScanTaskId, Integer pageNumber, Integer pageSize) {
         return this.baseMapper.pageUnbindData(new Page<>(pageNumber, pageSize), paperScanTaskId);
@@ -50,8 +59,6 @@ public class PaperLibraryServiceImpl extends ServiceImpl<PaperLibraryMapper, Pap
 
     @Override
     public boolean bind(Long paperLibraryId, Long paperScanTaskDetailId) {
-        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
-
         PaperScanTaskDetail paperScanTaskDetail = paperScanTaskDetailService.getById(paperScanTaskDetailId);
         if (paperScanTaskDetail == null) {
             throw ExceptionResultEnum.ERROR.exception("绑定对象有误,任务下无该考生,请刷新数据再试");
@@ -62,4 +69,44 @@ public class PaperLibraryServiceImpl extends ServiceImpl<PaperLibraryMapper, Pap
         return this.update(updateWrapper);
     }
 
+    @Override
+    public List<PaperLibraryResult> toBindPaper() {
+        SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
+        Long schoolId = SystemConstant.convertIdToLong(String.valueOf(ServletUtil.getRequestHeaderSchoolId()));
+
+        // 查询下一个待绑定任务
+        List<PaperLibrary> waitPaperLibraryList = this.baseMapper.selectBatchData(schoolId, sysUser.getId());
+        if (waitPaperLibraryList.isEmpty()) {
+            waitPaperLibraryList = createBindData(sysUser.getId(), schoolId);
+        }
+
+        List<PaperLibraryResult> paperLibraryResultList = new ArrayList<>();
+        if (!waitPaperLibraryList.isEmpty()) {
+            for (PaperLibrary paperLibrary : waitPaperLibraryList) {
+                PaperLibraryResult paperLibraryResult = new PaperLibraryResult();
+                BeanUtils.copyProperties(paperLibrary, paperLibraryResult);
+                // todo 图片地址
+                paperLibraryResult.setFileUrl("");
+            }
+        }
+        return paperLibraryResultList;
+    }
+
+    private List<PaperLibrary> createBindData(Long userId, Long schoolId) {
+        try {
+            lockService.waitlock(LockType.BIND_PAPER_TASK, schoolId);
+            List<PaperLibrary> paperLibraryList = this.baseMapper.listUnBindData(schoolId);
+            if (!paperLibraryList.isEmpty()) {
+                paperLibraryList.forEach(m -> m.setUserId(userId));
+                this.updateBatchById(paperLibraryList);
+            }
+            return paperLibraryList;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            lockService.unlock(LockType.BIND_PAPER_TASK, schoolId);
+        }
+        return new ArrayList<>();
+    }
+
 }

+ 18 - 1
paper-library-business/src/main/resources/mapper/PaperLibraryMapper.xml

@@ -89,8 +89,25 @@
                 AND pl.paper_scan_task_detail_id = pstd.id
         <where>
             <if test="paperScanTaskId != null">
-                and pstd.paper_scan_task_id = #{paperScanTaskId}
+                AND pstd.paper_scan_task_id = #{paperScanTaskId}
             </if>
         </where>
     </select>
+    <select id="listUnBindData" resultMap="BaseResultMap">
+        <include refid="Base_Column_List"></include>
+        <where>
+            school_id = #{schoolId}
+            AND user_id is null limit 10
+        </where>
+        ORDER BY paper_scan_task_id, crate_time
+    </select>
+    <select id="selectBatchData" resultMap="BaseResultMap">
+        <include refid="Base_Column_List"></include>
+        <where>
+            school_id = #{schoolId}
+            AND user_id = #{userId}
+            AND paper_scan_task_detail_id is null
+            limit 10
+        </where>
+    </select>
 </mapper>

+ 19 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockProvider.java

@@ -0,0 +1,19 @@
+package com.qmth.paper.library.common.lock;
+
+
+public interface LockProvider {
+
+    void waitLock(LockType type, String key);
+
+    boolean tryLock(LockType type, String key);
+
+    void unlock(LockType type, String key);
+
+    boolean isLocked(LockType type, String key);
+
+    void watch(LockType type, String key);
+
+    void unwatch(LockType type, String key);
+
+    void clear();
+}

+ 106 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockService.java

@@ -0,0 +1,106 @@
+package com.qmth.paper.library.common.lock;
+
+import com.qmth.paper.library.common.lock.impl.CustomLockProvider;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component("lockService")
+public class LockService implements InitializingBean, ApplicationContextAware {
+
+    protected static final Logger log = LoggerFactory.getLogger(LockService.class);
+
+    private static final String KEY_JOINER = "\t";
+
+    private ApplicationContext context;
+
+    private LockProvider provider;
+
+    /**
+     * 尝试获取排他锁,立即返回获取结果
+     *
+     * @param type
+     * @param keys
+     * @return
+     */
+    public boolean trylock(LockType type, Object... keys) {
+        return provider.tryLock(type, getKeys(keys));
+    }
+
+    /**
+     * 等待获取排他锁,线程阻塞直到成功获取
+     *
+     * @param type
+     * @param keys
+     */
+    public void waitlock(LockType type, Object... keys) {
+        provider.waitLock(type, getKeys(keys));
+    }
+
+    /**
+     * 释放已获取的排他锁
+     *
+     * @param type
+     * @param keys
+     */
+    public void unlock(LockType type, Object... keys) {
+        provider.unlock(type, getKeys(keys));
+    }
+
+    /**
+     * 检测排他锁是否已被获取
+     *
+     * @param type
+     * @param keys
+     * @return
+     */
+    public boolean isLocked(LockType type, Object... keys) {
+        return provider.isLocked(type, getKeys(keys));
+    }
+
+    /**
+     * 等待获取可重入的读锁
+     *
+     * @param type
+     * @param keys
+     */
+    public void watch(LockType type, Object... keys) {
+        provider.watch(type, getKeys(keys));
+    }
+
+    /**
+     * 释放已获取的读锁
+     *
+     * @param type
+     * @param keys
+     */
+    public void unwatch(LockType type, Object... keys) {
+        provider.unwatch(type, getKeys(keys));
+    }
+
+    /**
+     * 释放长时间未使用的锁
+     */
+    public void clear() {
+        provider.clear();
+    }
+
+    private String getKeys(Object... keys) {
+        return StringUtils.join(keys, KEY_JOINER);
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.provider = this.context.getBean(CustomLockProvider.class);
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext context) throws BeansException {
+        this.context = context;
+    }
+}

+ 16 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockType.java

@@ -0,0 +1,16 @@
+package com.qmth.paper.library.common.lock;
+
+public enum LockType {
+    BIND_SCAN_USER("绑定扫描员"), BIND_PAPER_TASK("绑定图片任务");
+
+    private String name;
+
+    private LockType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+}

+ 99 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/impl/CustomLockProvider.java

@@ -0,0 +1,99 @@
+package com.qmth.paper.library.common.lock.impl;
+
+import com.qmth.paper.library.common.lock.LockProvider;
+import com.qmth.paper.library.common.lock.LockType;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * 自己实现的内存锁控制
+ *
+ * @author luoshi
+ */
+@Component("customLockProvider")
+public class CustomLockProvider implements LockProvider {
+
+    private Map<LockType, Map<String, ReadWriteLock>> lockMap = new HashMap<>();
+
+    @Override
+    public void waitLock(LockType type, String key) {
+        getLock(type, key).write();
+    }
+
+    @Override
+    public boolean tryLock(LockType type, String key) {
+        return getLock(type, key).tryWrite();
+    }
+
+    @Override
+    public boolean isLocked(LockType type, String key) {
+        return getLock(type, key).writing();
+    }
+
+    @Override
+    public void unlock(LockType type, String key) {
+        getLock(type, key).unWrite();
+    }
+
+    @Override
+    public void watch(LockType type, String key) {
+        getLock(type, key).read();
+    }
+
+    @Override
+    public void unwatch(LockType type, String key) {
+        getLock(type, key).unRead();
+    }
+
+    private ReadWriteLock getLock(LockType type, String key) {
+        Map<String, ReadWriteLock> map = lockMap.get(type);
+        if (map == null) {
+            synchronized (lockMap) {
+                map = lockMap.get(type);
+                if (map == null) {
+                    map = new HashMap<>();
+                    lockMap.put(type, map);
+                }
+            }
+        }
+
+        ReadWriteLock lock = map.get(key);
+        if (lock == null) {
+            synchronized (map) {
+                lock = map.get(key);
+                if (lock == null) {
+                    lock = new ReadWriteLock();
+                    map.put(key, lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    public void clear() {
+        if (lockMap.isEmpty()) {
+            return;
+        }
+        synchronized (lockMap) {
+            for (Map<String, ReadWriteLock> map : lockMap.values()) {
+                Set<String> keys = new HashSet<>();
+                for (Entry<String, ReadWriteLock> entry : map.entrySet()) {
+                    if (!entry.getValue().writing() && entry.getValue().readCount() == 0) {
+                        keys.add(entry.getKey());
+                    }
+                }
+                for (String key : keys) {
+                    map.remove(key);
+                }
+                keys.clear();
+            }
+        }
+    }
+
+}

+ 100 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/impl/JdkLockProvider.java

@@ -0,0 +1,100 @@
+package com.qmth.paper.library.common.lock.impl;
+
+import com.qmth.paper.library.common.lock.LockProvider;
+import com.qmth.paper.library.common.lock.LockType;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * JVM内存实现的锁控制
+ *
+ * @author luoshi
+ */
+@Component("jdkLockProvider")
+public class JdkLockProvider implements LockProvider {
+
+    private Map<LockType, Map<String, ReentrantReadWriteLock>> lockMap = new HashMap<>();
+
+    @Override
+    public void waitLock(LockType type, String key) {
+        getLock(type, key).writeLock().lock();
+    }
+
+    @Override
+    public boolean tryLock(LockType type, String key) {
+        return getLock(type, key).writeLock().tryLock();
+    }
+
+    @Override
+    public boolean isLocked(LockType type, String key) {
+        return getLock(type, key).isWriteLocked();
+    }
+
+    @Override
+    public void unlock(LockType type, String key) {
+        getLock(type, key).writeLock().unlock();
+    }
+
+    @Override
+    public void watch(LockType type, String key) {
+        getLock(type, key).readLock().lock();
+    }
+
+    @Override
+    public void unwatch(LockType type, String key) {
+        getLock(type, key).readLock().unlock();
+    }
+
+    private ReentrantReadWriteLock getLock(LockType type, String key) {
+        Map<String, ReentrantReadWriteLock> map = lockMap.get(type);
+        if (map == null) {
+            synchronized (lockMap) {
+                map = lockMap.get(type);
+                if (map == null) {
+                    map = new HashMap<>();
+                    lockMap.put(type, map);
+                }
+            }
+        }
+
+        ReentrantReadWriteLock lock = map.get(key);
+        if (lock == null) {
+            synchronized (map) {
+                lock = map.get(key);
+                if (lock == null) {
+                    lock = new ReentrantReadWriteLock();
+                    map.put(key, lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    public void clear() {
+        if (lockMap.isEmpty()) {
+            return;
+        }
+        synchronized (lockMap) {
+            for (Map<String, ReentrantReadWriteLock> map : lockMap.values()) {
+                Set<String> keys = new HashSet<>();
+                for (Entry<String, ReentrantReadWriteLock> entry : map.entrySet()) {
+                    if (!entry.getValue().isWriteLocked() && entry.getValue().getReadLockCount() == 0) {
+                        keys.add(entry.getKey());
+                    }
+                }
+                for (String key : keys) {
+                    map.remove(key);
+                }
+                keys.clear();
+            }
+        }
+    }
+
+}

+ 134 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/impl/ReadWriteLock.java

@@ -0,0 +1,134 @@
+package com.qmth.paper.library.common.lock.impl;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * 简单读写锁实现<br>
+ * 0表示空闲状态,-1表示正在写,>0表示正在读
+ *
+ * @author luoshi
+ */
+public class ReadWriteLock {
+
+    private static ReadOperator readOperator = new ReadOperator();
+
+    private static UnReadOperator unreadOperator = new UnReadOperator();
+
+    private AtomicInteger value;
+
+    public ReadWriteLock() {
+        this.value = new AtomicInteger(0);
+    }
+
+    public int read() {
+        int result = 0;
+        while ((result = value.updateAndGet(readOperator)) < 1) {
+            ;
+        }
+        return result;
+    }
+
+    public int unRead() {
+        if (value.get() < 1) {
+            throw new RuntimeException("unread error");
+        }
+        return value.updateAndGet(unreadOperator);
+    }
+
+    public int readCount() {
+        return Math.max(0, value.get());
+    }
+
+    public int write() {
+        while (!value.compareAndSet(0, -1)) {
+            ;
+        }
+        return -1;
+    }
+
+    public boolean tryWrite() {
+        return value.compareAndSet(0, -1);
+    }
+
+    public int unWrite() {
+        while (!value.compareAndSet(-1, 0)) {
+            ;
+        }
+        return 0;
+    }
+
+    public boolean writing() {
+        return value.get() == -1;
+    }
+
+    static class ReadOperator implements IntUnaryOperator {
+
+        @Override
+        public int applyAsInt(int operand) {
+            return operand >= 0 ? operand + 1 : operand;
+        }
+
+    }
+
+    static class UnReadOperator implements IntUnaryOperator {
+
+        @Override
+        public int applyAsInt(int operand) {
+            return operand >= 1 ? operand - 1 : operand;
+        }
+
+    }
+
+    static class LockTestThread implements Runnable {
+
+        private ReadWriteLock lock;
+
+        private int number;
+
+        public LockTestThread(int number, ReadWriteLock lock) {
+            this.lock = lock;
+            this.number = number;
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < 10000; i++) {
+                if (Math.random() < 0.7) {
+                    System.out.println(
+                            "[thread-" + number + "]   read: " + lock.read() + "[" + System.currentTimeMillis() + "]");
+                    try {
+                        Thread.sleep(100 * ((i % 10) + 1));
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println("[thread-" + number + "] unread: " + lock.unRead() + "["
+                            + System.currentTimeMillis() + "]");
+                } else {
+                    System.out.println(
+                            "[thread-" + number + "]  write:" + lock.write() + "[" + System.currentTimeMillis() + "]");
+                    try {
+                        Thread.sleep(100 * ((i % 10) + 1));
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println("[thread-" + number + "]unwrite: " + lock.unWrite() + "["
+                            + System.currentTimeMillis() + "]");
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) {
+        ExecutorService executor = Executors.newFixedThreadPool(5);
+        final ReadWriteLock lock = new ReadWriteLock();
+        for (int i = 0; i < 5; i++) {
+            executor.submit(new LockTestThread(i + 1, lock));
+        }
+
+        executor.shutdown();
+    }
+
+}

+ 4 - 5
paper-library/src/main/java/com/qmth/paper/library/api/PaperLibraryController.java

@@ -74,12 +74,11 @@ public class PaperLibraryController {
         return ResultUtil.ok(paperLibraryService.bind(paperLibraryId, paperScanTaskDetailId));
     }
 
-    @ApiOperation(value = "确定(下一张)")
-    @PostMapping("/next")
+    @ApiOperation(value = "处理")
+    @PostMapping("/to_bind")
     @ApiResponses({@ApiResponse(code = 200, message = "确定成功", response = Result.class)})
-    public Result next(@ApiParam(value = "主键") @RequestParam(required = false) Long id) {
-        // todo 20220930 取任务
-        return ResultUtil.ok();
+    public Result next() {
+        return ResultUtil.ok(paperLibraryService.toBindPaper());
     }
 
 }