You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularJS重复注册问题:如何阻止同一账号/邮箱重复提交?

Fixing Duplicate Registration Issues for Username/Email

Let's walk through why this problem is happening and how to resolve it effectively—since relying solely on front-end checks isn't enough, we'll cover both front-end and back-end fixes.

Why the Current Setup Fails

Your front-end checks for existing users by comparing against the $scope.volonteri list loaded on page init. Here's the flaw:

  • When a user submits the form quickly multiple times, the first new user hasn't been saved to the back-end (or pulled back into the front-end via init()) before the second submission happens. So the front-end doesn't see the new user in its local list and allows the duplicate submission.
  • Worse, your back-end doesn't perform any duplicate checks at all—it just overwrites existing entries with the same username (since it uses put() on a Map) and allows duplicate emails entirely.

Step 1: Front-End Improvements (Prevent Accidental Duplicate Clicks)

First, let's stop users from accidentally clicking submit multiple times, and fix the front-end check logic:

Updated Controller Code

app.controller('volonterController', function($scope, volonterFactory, teritorijaFactory) {
    function init() {
        console.log('volonterController.Init');
        volonterFactory.getVolonteri().success(function (data) {
            $scope.volonteri = data;
        });
        teritorijaFactory.getTeritorije().success(function (data2) {
            $scope.teritorije = data2;
        });
    }
    init();
    
    // Track submission state to disable button
    $scope.isSubmitting = false;

    $scope.addVolonter = function(volonter) {
        volonterFactory.addVolonter(volonter).success(function(data) {
            toast('Volonter ' + volonter.username + " registered.");
            // Optional: Add the new user to local list immediately to avoid waiting for init()
            $scope.volonteri.push(volonter);
            $scope.isSubmitting = false;
        }).error(function(error) {
            // Handle back-end duplicate error
            alert(error.message);
            $scope.isSubmitting = false;
        });
    };

    $scope.submit1 = function() {
        if ($scope.isSubmitting) return; // Block duplicate clicks
        $scope.isSubmitting = true;

        $scope.volonter.state = "active";
        $scope.alreadyExists = false;
        var duplicateMessage = '';

        // Optimize check: break early when duplicate found
        for(var i=0; i < $scope.volonteri.length; i++) {
            if($scope.volonteri[i].username===$scope.volonter.username) {
                duplicateMessage = 'Volonter with the given username already exists.';
                $scope.alreadyExists = true;
                break;
            }
            if($scope.volonteri[i].email===$scope.volonter.email) {
                duplicateMessage = 'That email address is already in use.';
                $scope.alreadyExists = true;
                break;
            }
        }

        if($scope.alreadyExists) {
            alert(duplicateMessage);
            $scope.isSubmitting = false;
        } else {
            $scope.addVolonter($scope.volonter);
            // Remove init() here—we added the user to local list in addVolonter success, or let init() run on next page load if needed
        }
    }
});

Key Front-End Changes:

  • Added $scope.isSubmitting to disable the submit button during processing, preventing multiple clicks.
  • Optimized the duplicate check to break early and show only one alert instead of multiple.
  • Added an error callback to handle back-end validation errors.
  • Optional: Added the new user to the local volonteri list immediately after successful submission, so subsequent checks see it right away.

Step 2: Back-End Validation (Critical for Security & Reliability)

Front-end checks can be bypassed (e.g., someone directly calling your API with curl/postman), so you must add duplicate validation on the back-end. Here's how to update your Java REST method:

Updated Back-End Code

@POST
@Path("/addVolonter")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response addVolonter(Volonter v) {
    Map<String, Volonter> volonteriMap = getFileData().getVolonteri();

    // Check for duplicate username
    if (volonteriMap.containsKey(v.getUsername())) {
        return Response.status(Response.Status.CONFLICT)
                .entity("{\"message\": \"Volonter with the given username already exists.\"}")
                .build();
    }

    // Check for duplicate email (optimize this with a separate Map<Email, Volonter> if you have many users)
    boolean emailExists = volonteriMap.values().stream()
            .anyMatch(volonter -> volonter.getEmail().equals(v.getEmail()));
    if (emailExists) {
        return Response.status(Response.Status.CONFLICT)
                .entity("{\"message\": \"That email address is already in use.\"}")
                .build();
    }

    // If no duplicates, add the user
    volonteriMap.put(v.getUsername(), v);
    System.out.println("Volonter " + v.getUsername() + " added.");
    return Response.ok("{\"message\": \"OK\"}").build();
}

Key Back-End Changes:

  • Replaced returning a plain String with Response to send proper HTTP status codes (409 Conflict for duplicates).
  • Added checks for both duplicate username and email before saving the user.
  • Returns a JSON error message that the front-end can display to the user.
  • Note: For better performance with large user lists, consider adding a separate Map<String, Volonter> indexed by email instead of streaming through all values each time.

If your app has high traffic, you might still get duplicate submissions if two requests check for duplicates at the exact same time (before either is saved). To fix this:

  • Use thread-safe data structures (e.g., ConcurrentHashMap instead of a regular HashMap for volonteriMap).
  • Wrap the check-and-save logic in a synchronized block or use atomic operations to ensure only one request can modify the map at a time.

Final Notes

Always remember: front-end validation is for user experience, back-end validation is for security and data integrity. Never rely solely on front-end checks to prevent invalid data from entering your system.

内容的提问来源于stack exchange,提问作者newdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:22:22