Japanese Controllers

Last updated by admin 4 years ago

Grails ???????

??????????

{excerpt:hidden=true} A controller handles requests and creates or prepares the response. They can generate the response or delegate to a view. To create a controller simply create a class whose name ends with "Controller" and place it within the "grails-app/controllers" directory.{excerpt} ?????????????????????????????????????????????????????????????????????????????????????"Controller"???????????"grails-app/controllers"??????????????

{excerpt:hidden=true} The first part of your controller name is mapped to a URI and each action defined within your controller maps to URI within the controller name URI.{excerpt} ????????????????URI????????????????????????????URI?????????????

{excerpt:hidden=true} Controllers are request-scoped.  A new instance is created for each request. {excerpt} ???????????????????? ??????????????????????? 

Grails??????????

{excerpt:hidden=true} If you're lazy you can create a controller using the "create-controller" target which will prompt for the name of your controller:{excerpt} ??????????"create-controller" ??????????????????????????????????????????

grails create-controller
{excerpt:hidden=true} For example if we typed "book" the following controller would be created:{excerpt} ??? "book" ???????????????????????????
class BookController { … }
{excerpt:hidden=true} BookController maps to the <...>/book URI. Note that grails has done no special configuration in the background, all this is doing os creating you a controller from a template.{excerpt} BookController??<...>/book URI?????????Grails????????????????????????????????????????????????????????

????????

{excerpt:hidden=true} A controller can have multiple closure properties. Each of these properties maps to a URI:{excerpt} ??????????????????????????????????????????????URI?????????

class BookController {
    def list = {

// do controller logic // create model

return model }; }

{excerpt:hidden=true} This example maps to the <...>/book/list URI. If only one closure property is present the default URI for a controller maps to this property. Alternatively you can define an "index" action which is the action that handles requests when no action is specified in the URI i.e. <...>/book{excerpt} ??????<...>/book/list ??????????????????????1????????????????????URI????????? ?????????????URI??????????? (<...>/book ????)????????????????"index" ??????????????????

?????????????

{excerpt:hidden=true} There are 2 ways to set the default action (ie the action that is executed if no only the controller name is included in the uri), the simplest way is to merely create an action called index ??????????????????2?????????(????????uri??????????????????????)????????? "index" ??????????????????

def index = {
   redirect(action:list)
}
{excerpt:hidden=true} Alternatively you can set it explicity with the "defaultAction" property:{excerpt} ????? ???? "defaultAction" ????????????????????
def defaultAction = "list"

????????????? {excerpt:hidden=true} Restricting Access To Actions {excerpt}

{excerpt:hidden=true} By default all controller actions are accessible using any HTTP request method (GET, PUT, POST, etc...).&nbsp; The documentation for HTTP Method Restrictions explains how to restrict access to certain actions. {excerpt} ???????????????????????????????????????HTTP?????????????????????????????????????????

request??????session??????

{excerpt:hidden=true} Every controller has a number of properties inject into them at runtime, these make it possible to access the request, session etc. For a full reference on these please see the Dynamic Methods Reference {excerpt} ????????????????request?session?????????????????????????????????????? ????????????????????????????

class BookController {
    def find = {
        def findBy = params["findBy"]
        def appContext = servletContext["appContext"]
        def loggedUser = session["logged_user"]

// do stuff // return model return model }; }

????????????? {excerpt:hidden=true} Using Flash Scope {excerpt}

{excerpt:hidden=true} Flash scope is a concept introduction by Rails and essentially is a temporary store for attributes that should be available for the next request and the request only, after which they are cleared. This is useful for setting a message directly before redirection for example: {excerpt} ???????????Rails???????????????????????????????????????????????????????????(????????????????)????????????????????????????????????

def delete = {
    def b = Book.get( params['id'] )
    if(!b) {
        flash['message'] = "User not found for id ${params['id']}"
        redirect(action:list)
    }
    … // remaining code
}

???????????????????

{excerpt:hidden=true} Request parameters get passed into web applications as strings, causing a typical scenario of having to convert each string value into its equivalent object representation. With Grails domain classes this is made simple by the "properties" property: {excerpt} ????????????????????????????????????????????????????????????????Grails ????????? "properties" ????????????????????????

def save = {
  def b = new Book()
  b.properties = params
  b.save()
}
{excerpt:hidden=true} In the above example with one line of code the request parameters are auto-magically converted and set on the instance of Book. If you're using a command object or some other object that you want to bind data to you can use the "bindData" method present in controllers: {excerpt} ??????????1?????????????????Book??????????????????????????????????????????????????? "bindData" ????????????
def sc = new SaveCommand()
bindData(sc, params)

?????? {excerpt:hidden=true} Returning the Model {excerpt}

{excerpt:hidden=true} A model is essentially a map that the view uses when rendering. There are a couple of ways to return a model, the first way is to explicity return a map instance: {excerpt} ????????????????????????????????????????????????????1??????Map????????????????

def show = {
    def b = Book.get( params['id'] )
    return [ book : b ]
}
{excerpt:hidden=true} If no explicit model is returned the controller's properties will be used as the model thus allowing you to write code like this: {excerpt} ???????????????????????????????????????????????????????????????????
class BookController {
    List books
    List authors
    def list = {
           books = Book.list()
           authors = Author.list()
    }
}
{excerpt:hidden=true} In the above example the "books" and "authors" properties will be available in the view. A more advanced approach is to return an instance of the Spring ModelAndView class. {excerpt} ??????? "books" ? "authors" ?????????????????????????????? Spring ModelAndView?????????????????????????

??????????????

{excerpt:hidden=true} Sometimes its easier (typically with Ajax applications) to render snippets of text or code to the response directly from the controller. For this the highly flexible "render" method can be used: {excerpt} ????????????????????????????????????????????????(Ajax???)?????????? "render" ????????????

render "Hello World!"
{excerpt:hidden=true} The above code writes the text "Hello World!" to the response, other examples include: {excerpt} ??????????? "Hello World!" ?????? ??????
// ??????????? 
render {
   for(b in books) {
      div(id:b.id, b.title)
   }
}
// ????????????? 
render(view:'show')
// ?????????????????????????????? 
render(template:'book_template', collection:Book.list())
// ?????????????????????????????? 
render(text:"<xml>some xml</xml>",contentType:"text/xml",encoding:"UTF-8")

?????????????&?????? {excerpt:hidden=true} Action Redirection & Chaining {excerpt}

{excerpt:hidden=true} Actions can be redirected using the "redirect" method present in all controllers: {excerpt} ??????? "redirect" ????????????????????????????????

class OverviewController {
    def login = {}

def find = { if(!session["logged_user"]) redirect(action:login) ..... }; }

{excerpt:hidden=true} The redirect method expects either another closure within the same controller class or a string URI for calling another controller: {excerpt} ??????????????????????????????????URI???????????????????????????
redirect(action:login)
// ?? 
redirect(action:"/another/action")
// ?? 
redirect(controller:'home',action:'index')
{excerpt:hidden=true} Parameters can be optionally passed from one action to the next using the params argument of the method: {excerpt} ???????params ????????????????????????????
redirect(action:"/another/action", params:["myparam":"myvalue"])
{excerpt:hidden=true} These params are made available through the "params" dynamic property that also accesses request parameters. If a parameter is specified with the same name as a request parameter the request parameter is overridden and the controller parameter used. {excerpt} ????params ????????????????? "params" ???????????????????????????????????????????????????????????????????????????????????????

{excerpt:hidden=true} Actions can also be chained. Chaining allows the model to be retained from one action to the next. For example calling the "firstInChain" action: {excerpt} ?????????????????????????????????????????? "firstInChain" ?????????????

class ChainController {
    def firstInChain = {
        chain(action:secondInChain,model:["step1":new Object()])
    }
    def secondInChain = {
        chain(action:thirdInChain,model:["step2":new Object()])
    };
    def thirdInChain= {
        return ["step3":new Object()])
    };
}
{excerpt:hidden=true} Results in the model: {excerpt} ????????
["step1":object1, "step2":object2, "step3":object3]
{excerpt:hidden=true} The model can be accessed in subsequent controller actions in the chain via the "chainModel" map. This dynamic property only exists in actions following the call to "chain": {excerpt} ????????????????? "chainModel" Map ???????????????????????????? "chain" ??????????????????
class ChainController {

def nextInChain = { def model = chainModel["myModel"] ..... }; }

{excerpt:hidden=true} Like the "redirect" method you can also pass parameters to the chain method: {excerpt} "redirect" ???????????????????????????
chain(action:"/another/action", model:["step1":object1], params:["myparam":"param1"])

????????????? {excerpt:hidden=true} Action Interceptors {excerpt}

?? {excerpt:hidden=true} Introduction {excerpt}

{excerpt:hidden=true} Often it is useful to intercept processing based on either request, session or application state. This can be achieved via action interceptors. There are currently 2 types of interceptors: before and after. {excerpt} ??????????????????????????????????????????????????????????????????????????2???????????????? before ? after

Before ??????? {excerpt:hidden=true} Before Interception {excerpt}

{excerpt:hidden=true} The 'before' interceptor intercepts processing before the action is executed. If it returns 'false' then the following action will not be executed. The interceptor can be defined for all actions as follows: {excerpt} 'before' ???????????????????????????????"false" ?????????????????????????????????????????????????????

def beforeInterceptor = {
       println "Tracing action ${actionUri}"
}
{excerpt:hidden=true} The above will be executed before all actions and does not interfere with processing. A common use case is however for authentication: {excerpt} ????????????????????????????????????????????????
def beforeInterceptor = [action:this.&auth,except:'login']
// defined as a regular method so its private
def auth() {
     if(!session.user) {
            redirect(action:'login')
            return false
     }
}
def login = {
     // display login page
}
{excerpt:hidden=true} The above code defines a method called 'auth'. A method is used so that it is not exposed as an action to the outside world (i.e. it is private). The 'beforeInterceptor' then defines an interceptor that is used on all actions 'except' the login action and is told to execute the 'auth' method. The 'auth' method is referenced using Groovy's method pointer syntax, within the method itself it detects whether there is a user in the session otherwise it redirects to the login action and returns false, instruction the intercepted action not to be processed. {excerpt} ????????'auth' ????????????????????????????????????????????(?????private??)?login???????(except:'login')??????????'auth' ???????????? 'beforeInterceptor' ?????????????user??????????????????????????????false??? 'auth'?????Groovy????????????????????

After ??????? {excerpt:hidden=true} After Interception {excerpt}

{excerpt:hidden=true} To define an interceptor that is executed after an action use the 'afterInterceptor' property: {excerpt} ?????????????????????????????????? 'afterInterceptor' ?????????????

def afterInterceptor = { model ->
       println "Tracing action ${actionUri}"
}
{excerpt:hidden=true} The after interceptor takes the resulting model as an argument and can hence perform post manipulation of the model or response. {excerpt} after ?????????????????????????????????????????????????????????????????

????????? {excerpt:hidden=true} Interception Conditions {excerpt}

{excerpt:hidden=true} Rails users will be familiar with the authentication example and how the 'except' condition was used when executing the interceptor (interceptors are called 'filters' in Rails, this terminology conflicts with the servlet filter terminology in Java land): {excerpt} Rails???????????????????????????? 'except' ??????????????????????????(????????Rails?? 'filters' ??????????????Java?servlet?????????????)

def beforeInterceptor = [action:this.&auth,except:'login']
{excerpt:hidden=true} This executes the interceptor for all actions except the specified action. A list of actions can also be defined as follows: {excerpt} ??????????????(except)???????????????????????????????????????
def beforeInterceptor = [action:this.&auth,except:['login','register']]
{excerpt:hidden=true} The other supported condition is 'only', this executes the interceptor for only the specified actions: {excerpt} ???? 'only' (??) ?????????????????????????????????
def beforeInterceptor = [action:this.&auth,only:['secure']]

???????????? {excerpt:hidden=true} Handling File Uploads {excerpt}

{excerpt:hidden=true} To upload a file the first step is to create a multipart form like the one below: {excerpt} ??????????????????????????????????????????

Upload Form: <br />
		<g:form action="upload" method="post" enctype="multipart/form-data">
			<input type="file" name="myFile" />
			<input type="submit" />
		</g:form>
{excerpt:hidden=true} There are then a number of ways to handle the file upload. The first way is to work with the Spring MultipartFile instance directly: {excerpt} ?????????????????????????????????????Spring MultipartFile ???????????????
def upload = {
    def f = request.getFile('myFile')
    if(!f.empty) {
      f.transferTo( new File('someotherloc') )
    }
    else {
       flash.message = 'file cannot be empty'
       redirect(action:'uploadForm')
    }
}
{excerpt:hidden=true} This is clearly handy for doing transfers to other destinations and manipulating the file directly (you can also open an InputStream, see javadoc). The next way to deal with file uploads is to bind the file's contents to a domain class or command bean. Lets look at a domain class example say you have an 'Image' domain class like the below: {excerpt} ???????????????????????????????(InputStream??????????)? ???????????????????????????????????????????????????????????'Image' ??????????????????????
class Image {
   byte[] myFile
}
{excerpt:hidden=true} Now when we do the usual set of properties like the below: {excerpt} ????????????????????
def img = new Image()
img.properties = params
{excerpt:hidden=true} The contents of the file will automatically be converted into a byte[] and set on the image domain class. It is also possible to set the contents of the file as a string by changing the type of the 'myFile' property on the image to a String type: {excerpt} ??????????????byte[]????? image????????????????'myFile'???String?????????????????????????????
class Image {
   String myFile
}
{excerpt:hidden=true} The final way to do this is via the 'bindData' method which you can use in combination with a command object. Say we have a command object like the below: {excerpt} ????????????????????????????? 'bindData' ???????????????????????????????????
class UploadCommand {
   byte[] myFile
}
{excerpt:hidden=true} We can then use it in the controller like this: {excerpt} ?????????????????????
def upload = {
   def uc = new UploadCommand()
   bindData(uc, params)
   assert uc.myFile != null
}

?????????????? {excerpt:hidden=true} Injecting services into controllers {excerpt}

{excerpt:hidden=true} Controllers may use services to delegate requests to business logic. To have these resources injected add corresponding properties to the controller. {excerpt} ??????????????????????????????????????????????????????????????????????????????????

CountryService countryService