Java Rest最佳实践

我是不熟悉Web服务的新手,并且有新手q'。我已经创建了一个rest类,并希望使用helper类来处理某些操作。因此,例如,我创建了以下服务:

/*! rangeslider.js - v2.3.0 | (c) 2016 @andreruffert | MIT license | https://github.com/andreruffert/rangeslider.js */
(function(factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'],factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function($) {
    'use strict';

    // Polyfill Number.isnaN(value)
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isnaN
    Number.isnaN = Number.isnaN || function(value) {
        return typeof value === 'number' && value !== value;
    };

    /**
     * Range feature detection
     * @return {Boolean}
     */
    function supportsrange() {
        var input = document.createElement('input');
        input.setattribute('type','range');
        return input.type !== 'text';
    }

    var pluginName = 'rangeslider',pluginIdentifier = 0,hasInputRangeSupport = supportsrange(),defaults = {
            polyfill: true,orientation: 'horizontal',rangeclass: 'rangeslider',disabledClass: 'rangeslider--disabled',activeclass: 'rangeslider--active',horizontalClass: 'rangeslider--horizontal',verticalClass: 'rangeslider--vertical',fillClass: 'rangeslider__fill',handleclass: 'rangeslider__handle',startEvent: ['mousedown','touchstart','pointerdown'],moveEvent: ['mousemove','touchmove','pointermove'],endEvent: ['mouseup','touchend','pointerup']
        },constants = {
            orientation: {
                horizontal: {
                    dimension: 'width',direction: 'left',directionStyle: 'left',coordinate: 'x'
                },vertical: {
                    dimension: 'height',direction: 'top',directionStyle: 'bottom',coordinate: 'y'
                }
            }
        };

    /**
     * Delays a function for the given number of milliseconds,and then calls
     * it with the arguments supplied.
     *
     * @param  {Function} fn   [description]
     * @param  {Number}   wait [description]
     * @return {Function}
     */
    function delay(fn,wait) {
        var args = Array.prototype.slice.call(arguments,2);
        return setTimeout(function(){ return fn.apply(null,args); },wait);
    }

    /**
     * Returns a debounced function that will make sure the given
     * function is not triggered too much.
     *
     * @param  {Function} fn Function to debounce.
     * @param  {Number}   debounceDuration OPTIONAL. The amount of time in milliseconds for which we will debounce the function. (defaults to 100ms)
     * @return {Function}
     */
    function debounce(fn,debounceDuration) {
        debounceDuration = debounceDuration || 100;
        return function() {
            if (!fn.debouncing) {
                var args = Array.prototype.slice.apply(arguments);
                fn.lastReturnVal = fn.apply(window,args);
                fn.debouncing = true;
            }
            clearTimeout(fn.debounceTimeout);
            fn.debounceTimeout = setTimeout(function(){
                fn.debouncing = false;
            },debounceDuration);
            return fn.lastReturnVal;
        };
    }

    /**
     * Check if a `element` is visible in the DOM
     *
     * @param  {Element}  element
     * @return {Boolean}
     */
    function isHidden(element) {
        return (
            element && (
                element.offsetWidth === 0 ||
                element.offsetHeight === 0 ||
                // Also Consider native `<details>` elements.
                element.open === false
            )
        );
    }

    /**
     * Get hidden parentNodes of an `element`
     *
     * @param  {Element} element
     * @return {[type]}
     */
    function getHiddenParentNodes(element) {
        var parents = [],node    = element.parentNode;

        while (isHidden(node)) {
            parents.push(node);
            node = node.parentNode;
        }
        return parents;
    }

    /**
     * Returns dimensions for an element even if it is not visible in the DOM.
     *
     * @param  {Element} element
     * @param  {String}  key     (e.g. offsetWidth …)
     * @return {Number}
     */
    function getDimension(element,key) {
        var hiddenParentNodes       = getHiddenParentNodes(element),hiddenParentNodesLength = hiddenParentNodes.length,inlinestyle             = [],dimension               = element[key];

        // Used for native `<details>` elements
        function toggleOpenProperty(element) {
            if (typeof element.open !== 'undefined') {
                element.open = (element.open) ? false : true;
            }
        }

        if (hiddenParentNodesLength) {
            for (var i = 0; i < hiddenParentNodesLength; i++) {

                // Cache style attribute to restore it later.
                inlinestyle[i] = hiddenParentNodes[i].style.cssText;

                // visually hide
                if (hiddenParentNodes[i].style.setProperty) {
                    hiddenParentNodes[i].style.setProperty('display','block','important');
                } else {
                    hiddenParentNodes[i].style.cssText += ';display: block !important';
                }
                hiddenParentNodes[i].style.height = '0';
                hiddenParentNodes[i].style.overflow = 'hidden';
                hiddenParentNodes[i].style.visibility = 'hidden';
                toggleOpenProperty(hiddenParentNodes[i]);
            }

            // Update dimension
            dimension = element[key];

            for (var j = 0; j < hiddenParentNodesLength; j++) {

                // Restore the style attribute
                hiddenParentNodes[j].style.cssText = inlinestyle[j];
                toggleOpenProperty(hiddenParentNodes[j]);
            }
        }
        return dimension;
    }

    /**
     * Returns the parsed float or the default if it failed.
     *
     * @param  {String}  str
     * @param  {Number}  defaultvalue
     * @return {Number}
     */
    function tryParseFloat(str,defaultvalue) {
        var value = parseFloat(str);
        return Number.isnaN(value) ? defaultvalue : value;
    }

    /**
     * Capitalize the first letter of string
     *
     * @param  {String} str
     * @return {String}
     */
    function ucfirst(str) {
        return str.charAt(0).toUpperCase() + str.substr(1);
    }

    /**
     * Plugin
     * @param {String} element
     * @param {Object} options
     */
    function Plugin(element,options) {
        this.$window            = $(window);
        this.$document          = $(document);
        this.$element           = $(element);
        this.options            = $.extend( {},defaults,options );
        this.polyfill           = this.options.polyfill;
        this.orientation        = this.$element[0].getattribute('data-orientation') || this.options.orientation;
        this.onInit             = this.options.onInit;
        this.onSlide            = this.options.onSlide;
        this.onSlideEnd         = this.options.onSlideEnd;
        this.DIMENSION          = constants.orientation[this.orientation].dimension;
        this.DIRECTION          = constants.orientation[this.orientation].direction;
        this.DIRECTION_STYLE    = constants.orientation[this.orientation].directionStyle;
        this.COORDINATE         = constants.orientation[this.orientation].coordinate;

        // Plugin should only be used as a polyfill
        if (this.polyfill) {
            // Input range support?
            if (hasInputRangeSupport) { return false; }
        }

        this.identifier = 'js-' + pluginName + '-' +(pluginIdentifier++);
        this.startEvent = this.options.startEvent.join('.' + this.identifier + ' ') + '.' + this.identifier;
        this.moveEvent  = this.options.moveEvent.join('.' + this.identifier + ' ') + '.' + this.identifier;
        this.endEvent   = this.options.endEvent.join('.' + this.identifier + ' ') + '.' + this.identifier;
        this.toFixed    = (this.step + '').replace('.','').length - 1;
        this.$fill      = $('<div class="' + this.options.fillClass + '" />');
        this.$handle    = $('<div class="' + this.options.handleclass + '" />');
        this.$range     = $('<div class="' + this.options.rangeclass + ' ' + this.options[this.orientation + 'Class'] + '" id="' + this.identifier + '" />').insertAfter(this.$element).prepend(this.$fill,this.$handle);

        // visually hide the input
        this.$element.css({
            'position': 'absolute','width': '1px','height': '1px','overflow': 'hidden','opacity': '0'
        });

        // Store context
        this.handleDown = $.proxy(this.handleDown,this);
        this.handleMove = $.proxy(this.handleMove,this);
        this.handleEnd  = $.proxy(this.handleEnd,this);

        this.init();

        // Attach Events
        var _this = this;
        this.$window.on('resize.' + this.identifier,debounce(function() {
            // Simulate resizeEnd event.
            delay(function() { _this.update(false,false); },300);
        },20));

        this.$document.on(this.startEvent,'#' + this.identifier + ':not(.' + this.options.disabledClass + ')',this.handleDown);

        // Listen to programmatic value changes
        this.$element.on('change.' + this.identifier,function(e,data) {
            if (data && data.origin === _this.identifier) {
                return;
            }

            var value = e.target.value,pos = _this.getPositionFromValue(value);
            _this.setPosition(pos);
        });
    }

    Plugin.prototype.init = function() {
        this.update(true,false);

        if (this.onInit && typeof this.onInit === 'function') {
            this.onInit();
        }
    };

    Plugin.prototype.update = function(updateAttributes,triggerSlide) {
        updateAttributes = updateAttributes || false;

        if (updateAttributes) {
            this.min    = tryParseFloat(this.$element[0].getattribute('min'),0);
            this.max    = tryParseFloat(this.$element[0].getattribute('max'),100);
            this.value  = tryParseFloat(this.$element[0].value,Math.round(this.min + (this.max-this.min)/2));
            this.step   = tryParseFloat(this.$element[0].getattribute('step'),1);
        }

        this.handleDimension    = getDimension(this.$handle[0],'offset' + ucfirst(this.DIMENSION));
        this.rangeDimension     = getDimension(this.$range[0],'offset' + ucfirst(this.DIMENSION));
        this.maxHandlePos       = this.rangeDimension - this.handleDimension;
        this.grabPos            = this.handleDimension / 2;
        this.position           = this.getPositionFromValue(this.value);

        // Consider disabled state
        if (this.$element[0].disabled) {
            this.$range.addClass(this.options.disabledClass);
        } else {
            this.$range.removeclass(this.options.disabledClass);
        }

        this.setPosition(this.position,triggerSlide);
    };

    Plugin.prototype.handleDown = function(e) {
        e.preventDefault();
        this.$document.on(this.moveEvent,this.handleMove);
        this.$document.on(this.endEvent,this.handleEnd);

        // add active class because Firefox is ignoring
        // the handle:active pseudo selector because of `e.preventDefault();`
        this.$range.addClass(this.options.activeclass);

        // If we click on the handle don't set the new position
        if ((' ' + e.target.classname + ' ').replace(/[\n\t]/g,' ').indexOf(this.options.handleclass) > -1) {
            return;
        }

        var pos         = this.getRelativePosition(e),rangePos    = this.$range[0].getBoundingClientRect()[this.DIRECTION],handlePos   = this.getPositionFromNode(this.$handle[0]) - rangePos,setPos      = (this.orientation === 'vertical') ? (this.maxHandlePos - (pos - this.grabPos)) : (pos - this.grabPos);

        this.setPosition(setPos);

        if (pos >= handlePos && pos < handlePos + this.handleDimension) {
            this.grabPos = pos - handlePos;
        }
    };

    Plugin.prototype.handleMove = function(e) {
        e.preventDefault();
        var pos = this.getRelativePosition(e);
        var setPos = (this.orientation === 'vertical') ? (this.maxHandlePos - (pos - this.grabPos)) : (pos - this.grabPos);
        this.setPosition(setPos);
    };

    Plugin.prototype.handleEnd = function(e) {
        e.preventDefault();
        this.$document.off(this.moveEvent,this.handleMove);
        this.$document.off(this.endEvent,this.handleEnd);

        this.$range.removeclass(this.options.activeclass);

        // Ok we're done fire the change event
        this.$element.trigger('change',{ origin: this.identifier });

        if (this.onSlideEnd && typeof this.onSlideEnd === 'function') {
            this.onSlideEnd(this.position,this.value);
        }
    };

    Plugin.prototype.cap = function(pos,min,max) {
        if (pos < min) { return min; }
        if (pos > max) { return max; }
        return pos;
    };

    Plugin.prototype.setPosition = function(pos,triggerSlide) {
        var value,newPos;

        if (triggerSlide === undefined) {
            triggerSlide = true;
        }

        // snapping steps
        value = this.getvalueFromPosition(this.cap(pos,this.maxHandlePos));
        newPos = this.getPositionFromValue(value);

        // Update ui
        this.$fill[0].style[this.DIMENSION] = (newPos + this.grabPos) + 'px';
        this.$handle[0].style[this.DIRECTION_STYLE] = newPos + 'px';
        this.setvalue(value);

        // Update globals
        this.position = newPos;
        this.value = value;

        if (triggerSlide && this.onSlide && typeof this.onSlide === 'function') {
            this.onSlide(newPos,value);
        }
    };

    // Returns element position relative to the parent
    Plugin.prototype.getPositionFromNode = function(node) {
        var i = 0;
        while (node !== null) {
            i += node.offsetLeft;
            node = node.offsetParent;
        }
        return i;
    };

    Plugin.prototype.getRelativePosition = function(e) {
        // Get the offset DIRECTION relative to the viewport
        var ucCoordinate = ucfirst(this.COORDINATE),rangePos = this.$range[0].getBoundingClientRect()[this.DIRECTION],pageCoordinate = 0;

        if (typeof e.originalEvent['client' + ucCoordinate] !== 'undefined') {
            pageCoordinate = e.originalEvent['client' + ucCoordinate];
        }
        else if (
          e.originalEvent.touches &&
          e.originalEvent.touches[0] &&
          typeof e.originalEvent.touches[0]['client' + ucCoordinate] !== 'undefined'
        ) {
            pageCoordinate = e.originalEvent.touches[0]['client' + ucCoordinate];
        }
        else if(e.currentPoint && typeof e.currentPoint[this.COORDINATE] !== 'undefined') {
            pageCoordinate = e.currentPoint[this.COORDINATE];
        }

        return pageCoordinate - rangePos;
    };

    Plugin.prototype.getPositionFromValue = function(value) {
        var percentage,pos;
        percentage = (value - this.min)/(this.max - this.min);
        pos = (!Number.isnaN(percentage)) ? percentage * this.maxHandlePos : 0;
        return pos;
    };

    Plugin.prototype.getvalueFromPosition = function(pos) {
        var percentage,value;
        percentage = ((pos) / (this.maxHandlePos || 1));
        value = this.step * Math.round(percentage * (this.max - this.min) / this.step) + this.min;
        return Number((value).toFixed(this.toFixed));
    };

    Plugin.prototype.setvalue = function(value) {
        if (value === this.value && this.$element[0].value !== '') {
            return;
        }

        // Set the new value and fire the `input` event
        this.$element
            .val(value)
            .trigger('input',{ origin: this.identifier });
    };

    Plugin.prototype.destroy = function() {
        this.$document.off('.' + this.identifier);
        this.$window.off('.' + this.identifier);

        this.$element
            .off('.' + this.identifier)
            .removeAttr('style')
            .removeData('plugin_' + pluginName);

        // Remove the generated markup
        if (this.$range && this.$range.length) {
            this.$range[0].parentNode.removeChild(this.$range[0]);
        }
    };

    // A really lightweight plugin wrapper around the constructor,// preventing against multiple instantiations
    $.fn[pluginName] = function(options) {
        var args = Array.prototype.slice.call(arguments,1);

        return this.each(function() {
            var $this = $(this),data  = $this.data('plugin_' + pluginName);

            // Create a new instance.
            if (!data) {
                $this.data('plugin_' + pluginName,(data = new Plugin(this,options)));
            }

            // Make it possible to access methods from public.
            // e.g `$element.rangeslider('method');`
            if (typeof options === 'string') {
                data[options].apply(data,args);
            }
        });
    };

    return 'rangeslider.js is available in jQuery context e.g $(selector).rangeslider(options);';

}));

关于这种方法,我有几个问题:

这是实例化助手类的正确方法吗?还是应该创建一个构造函数并在那里实例化该类?例如:

   import statements...
   @Path("/UserResources")
   public class UserResource {
   //Create Spring application context
    static ClasspathXmlApplicationContext ctx = new 
    ClasspathXmlApplicationContext("classpath:/spring.xml");
    private UserResourceHelper urh = new UserResourceHelper(); // this is the helper 
    class UserProfileService userProfileService = ctx.getBean(UserProfileService.class);

    @POST
    @Path("/createUser")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createUser(@Context HttpServletRequest request,Object object) { 
      StringBuffer sb = new StringBuffer();
      User user = userProfileService.findByPrimaryKey(object); 
      sb.append(urh.createUser(object)); 
      return 
      Response.status(Status.CREATED.getStatusCode()).entity(result.toString()).build(); } }

在这种方法下,总是会有UserResourceHelper的新实例吗?

如果这样的话,这意味着并发正确不会有问题吗?即。 2个请求同时进入,而createUser方法接收到的第一个对象会突然被突然出现的第二个对象代替?

我正在将Hibernate用于ORM。按照我的代码示例实例化实体的方式是否正确?

感谢您的协助!

viktors 回答:Java Rest最佳实践

在这种方法下,总是会有UserResourceHelper的新实例吗?

yes. It always creates new instance

建议:

如果要为每个请求创建一个新服务,则可以将其作为服务而不是帮助程序类,并可以在控制器中自动连接该服务。

@Service
public class UserResourceService {

 }

并在控制器中

public class someController {

    @Autowired
    private UserResourceService userResourceService;

}

,

您可以在春季启动时使用@Autowire注释,它将自动创建类的实例

@Autowire
UserResourceHelper userResourceHelper;
本文链接:https://www.f2er.com/3022480.html

大家都在问