AMcoder - javascript, python, java, html, php, sql

Մուտք գործեք նիստի փոփոխական ServletContextListener-ում

Ես իրականացնում եմ բեռնման գործառույթ՝ օգտագործելով Grails, որտեղ հիմնականում օգտվողը կարող է վերբեռնել տեքստային ֆայլ, այնուհետև համակարգը կպահպանի այդ տեքստային ֆայլի յուրաքանչյուր տողը որպես տվյալների բազայի գրառում: Թեև բեռնումը լավ է աշխատում, ավելի մեծ ֆայլերը մշակելու համար ժամանակ է պահանջվում, և, հետևաբար, նրանք խնդրում են ունենալ առաջընթացի սանդղակ, որպեսզի օգտվողները կարողանան որոշել՝ արդյոք իրենց վերբեռնումը դեռ մշակվում է, թե իրական սխալ է տեղի ունեցել:

Դա անելու համար ես արեցի երկու URL-ի ստեղծում.

  • /upload որը փաստացի URL-ն է, որը ստանում է վերբեռնված տեքստային ֆայլը:
  • /upload/status?uploadToken=, որն իր uploadToken-ի հիման վրա վերադարձնում է որոշակի վերբեռնման կարգավիճակ:

Այն, ինչ ես արեցի, այն է, որ յուրաքանչյուր տող մշակելուց հետո ծառայությունը կթարմացնի նստաշրջանի մակարդակի հաշվիչի փոփոխականը.

// import ...

class UploadService {
    Map upload(CommonsMultipartFile record, GrailsParameterMap params) {
        Map response = [success: true]

        try {
            File file = new File(record.getOriginalFilename())
            FileUtils.writeByteArrayToFile(file, record.getBytes())
            HttpSession session = WebUtils.retrieveGrailsWebRequest().session
            List<String> lines = FileUtils.readLines(file, "UTF-8"), errors = []
            String uploadToken = params.uploadToken

            session.status.put(uploadToken,
                [message: "Checking content of the file of errors.",
                    size: lines.size(),
                    done: 0])

            lines.eachWithIndex { l, li ->
                // ... regex checking per line and appending any error to the errors List

                session.status.get(uploadToken).done++
            }

            if(errors.size() == 0) {
                session.status.put(uploadToken,
                    [message: "Persisting record to the database.",
                        size: lines.size(),
                        done: 0])

                lines.eachWithIndex { l, li ->
                    // ... Performs GORM manipulation here

                    session.status.get(uploadToken).done++
                }           
            }
            else {
                response.success = false
            }
        }
        catch(Exception e) {
            response.success = false
        }

        response << [errors: errors]

        return response
    }
}

Այնուհետև ստեղծեք պարզ WebSocket իրականացում, որը միանում է /upload/status?uploadToken= URL-ը: Խնդիրն այն է, որ ես չեմ կարող մուտք գործել նիստի փոփոխական POGO-ներում: Ես նույնիսկ փոխում եմ այդ POGO-ն Grails ծառայության, քանի որ կարծում էի, որ դա է խնդրի պատճառը, բայց ես դեռ չեմ կարող մուտք գործել նիստի փոփոխական:

// import ...

@ServerEndpoint("/upload/status")
@WebListener
class UploadEndpointService implements ServletContextListener {    
    @OnOpen
    public void onOpen(Session userSession) { /* ... */ }

    @OnClose
    public void onClose(Session userSession, CloseReason closeReason) { /* ... */ }

    @OnError
    public void onError(Throwable t) { /* ... */ }

    @OnMessage
    public void onMessage(String token, Session userSession) {
        // Both of these cause IllegalStateException
        def session = WebUtils.retrieveGrailsWebRequest().session
        def session = RequestContextHolder.currentRequestAttributes().getSession()

        // This returns the session id but I don't know what to do with that information.
        String sessionId = userSession.getHttpSessionId() 

        // Sends the upload status through this line    
        sendMessage((session.get(token) as JSON).toString(), userSession)
    }

    private void sendMessage(String message, Session userSession = null) {
        Iterator<Session> iterator = users.iterator()
        while(iterator.hasNext()) {
            iterator.next().basicRemote.sendText(message)
        }
    }
}

Եվ փոխարենը, ինձ սխալ է տալիս.

Պատճառված է IllegalStateException. Շղթայական կապով հարցում չի գտնվել. Դուք նկատի ունեք ատրիբուտների հարցումը իրական վեբ հարցումից դուրս, թե՞ հարցումն եք մշակում սկզբնապես ստացվող շղթայից դուրս: Եթե ​​դուք իրականում աշխատում եք վեբ հարցման շրջանակներում և դեռ ստանում եք այս հաղորդագրությունը, ձեր կոդը, հավանաբար, աշխատում է DispatcherServlet/DispatcherPortlet-ից դուրս: Այս դեպքում օգտագործեք RequestContextListener կամ RequestContextFilter՝ ընթացիկ հարցումը բացահայտելու համար:

Ես արդեն հաստատել եմ, որ վեբ վարդակն աշխատում է՝ ստիպելով այն ուղարկել ստատիկ String բովանդակություն: Բայց այն, ինչ ես ուզում եմ, այն է, որ կարողանամ ստանալ այդ հաշվիչը և սահմանել այն որպես ուղարկելու հաղորդագրություն: Ես օգտագործում եմ Grails 2.4.4-ը և Grails Spring Websocket հավելվածը, թեև խոստումնալից է թվում, հասանելի է միայն Grails 3-ից սկսած: Կա՞ արդյոք դրան հասնելու որևէ միջոց, կամ եթե ոչ, ի՞նչ մոտեցում պետք է օգտագործեմ:



Պատասխանները:


1

Շատ շնորհակալ եմ այս հարցի պատասխանին, որն ինձ մեծապես օգնեց լուծելու իմ խնդիրը:

Ես պարզապես փոփոխեցի իմ UploadEndpointService-ը նույնը, ինչ այդ պատասխանում էր, և այն որպես սպասարկման դաս դարձնելու փոխարեն, ես այն նորից դարձրի POGO: Ես նաև կազմաձևեցի դրա @Serverendpoint անոտացիան և ավելացրի configurator արժեքը: Ես նաև երկրորդ պարամետր եմ ավելացրել onOpen() մեթոդին: Ահա խմբագրված դասը.

import grails.converters.JSON
import grails.util.Environment
import javax.servlet.annotation.WebListener
import javax.servlet.http.HttpSession
import javax.servlet.ServletContext
import javax.servlet.ServletContextEvent
import javax.servlet.ServletContextListener
import javax.websocket.CloseReason
import javax.websocket.EndpointConfig
import javax.websocket.OnClose
import javax.websocket.OnError
import javax.websocket.OnMessage
import javax.websocket.OnOpen
import javax.websocket.server.ServerContainer
import javax.websocket.server.ServerEndpoint
import javax.websocket.Session
import org.apache.log4j.Logger
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.web.json.JSONObject
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.springframework.context.ApplicationContext

@ServerEndpoint(value="/ep/maintenance/attendance-monitoring/upload/status", configurator=GetHttpSessionConfigurator.class)
@WebListener
class UploadEndpoint implements ServletContextListener {
    private static final Logger log = Logger.getLogger(UploadEndpoint.class)
    private Session wsSession
    private HttpSession httpSession

    @Override
    void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.servletContext
        ServerContainer serverContainer = servletContext.getAttribute("javax.websocket.server.ServerContainer")

        try {
            if (Environment.current == Environment.DEVELOPMENT) {
                serverContainer.addEndpoint(UploadEndpoint)
            }

            ApplicationContext ctx = (ApplicationContext) servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
            GrailsApplication grailsApplication = ctx.grailsApplication
            serverContainer.defaultMaxSessionIdleTimeout = grailsApplication.config.servlet.defaultMaxSessionIdleTimeout ?: 0
        } catch (IOException e) {
            log.error(e.message, e)
        }
    }

    @Override
    void contextDestroyed(ServletContextEvent servletContextEvent) {
    }

    @OnOpen
    public void onOpen(Session userSession, EndpointConfig config) {
        this.wsSession = userSession
        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName())
    }

    @OnMessage
    public void onMessage(String message, Session userSession) {
        try {
            Map params = new JSONObject(message)
            if(httpSession.status == null) {
                params = [message: "Initializing file upload.",
                    size: 0,
                    token: 0]
                sendMessage((params as JSON).toString())
            }
            else {
                sendMessage((httpSession.status.get(params.token) as JSON).toString())
            }
        }
        catch(IllegalStateException e) {
        }
    }

    @OnClose
    public void onClose(Session userSession, CloseReason closeReason) {
        try {
            userSession.close()
        }
        catch(IllegalStateException e) {
        }
    }

    @OnError
    public void onError(Throwable t) {
        log.error(t.message, t)
    }

    private void sendMessage(String message, Session userSession=null) {
        wsSession.basicRemote.sendText(message)
    }
}

Իրական կախարդանքը տեղի է ունենում onOpen() մեթոդի շրջանակներում: Այնտեղ տեղի է ունենում նիստի փոփոխականի մուտքը:

05.03.2018
Նոր նյութեր

Օգտագործելով Fetch Vs Axios.Js-ը՝ HTTP հարցումներ կատարելու համար
JavaScript-ը կարող է ցանցային հարցումներ ուղարկել սերվեր և բեռնել նոր տեղեկատվություն, երբ դա անհրաժեշտ լինի: Օրինակ, մենք կարող ենք օգտագործել ցանցային հարցումը պատվեր ներկայացնելու,..

Տիրապետել հանգստության արվեստին. մշակողի ուղեցույց՝ ճնշման տակ ծաղկելու համար
Տիրապետել հանգստության արվեստին. մշակողի ուղեցույց՝ ճնշման տակ ծաղկելու համար Ինչպե՞ս հանգստացնել ձեր միտքը և աշխատեցնել ձեր պրոցեսորը: Ինչպես մնալ հանգիստ և զարգանալ ճնշման տակ...

Մեքենայի ուսուցում բանկային և ֆինանսների ոլորտում
Բարդ, խելացի անվտանգության համակարգերը և հաճախորդների սպասարկման պարզեցված ծառայությունները բիզնեսի հաջողության բանալին են: Ֆինանսական հաստատությունները, մասնավորապես, պետք է առաջ մնան կորի..

Ես AI-ին հարցրի կյանքի իմաստը, այն ինչ ասում էր, ցնցող էր:
Այն պահից ի վեր, երբ ես իմացա Արհեստական ​​ինտելեկտի մասին, ես հիացած էի այն բանով, թե ինչպես է այն կարողանում հասկանալ մարդկային նորմալ տեքստը, և այն կարող է առաջացնել իր սեփական արձագանքը դրա..

Ինչպես սովորել կոդավորումը Python-ում վագրի պես:
Սովորելու համար ծրագրավորման նոր լեզու ընտրելը բարդ է: Անկախ նրանից, թե դուք սկսնակ եք, թե առաջադեմ, դա օգնում է իմանալ, թե ինչ թեմաներ պետք է սովորել: Ծրագրավորման լեզվի հիմունքները, դրա..

C++-ի օրական բիթ(ե) | Ամենաերկար պալինդրոմային ենթաշարը
C++ #198-ի ամենօրյա բիթ(ե), Ընդհանուր հարցազրույցի խնդիր. Ամենաերկար պալինդրոմային ենթատող: Այսօր մենք կանդրադառնանք հարցազրույցի ընդհանուր խնդրին. Ամենաերկար palindromic substring...

Kydavra ICAReducer՝ ձեր տվյալների ծավալայինությունը նվազեցնելու համար
Ի՞նչ է ICAReducer-ը: ICAReducer-ն աշխատում է հետևյալ կերպ. այն նվազեցնում է նրանց միջև բարձր փոխկապակցված հատկանիշները մինչև մեկ սյունակ: Բավականին նման է PCAreducer-ին, չնայած այն..