天天看點

Springmvc常見問題

問題一:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Failed to introspect bean class [com.blog.controller.UserController] for lookup method metadata: could not find class that it depends on; nested exception is java.lang.NoClassDefFoundError: javax/mail/MessagingException

出現這種問題的原因是因為,以我個人部落格為例,我在注冊中用到了這個郵箱工具類,郵箱工具類預設抛出Exception和MessagingException異常,然後我去除了該工具類,但未将異常去掉,然後在項目啟動中直接報錯。如果是用jsp作為表現層直接到首頁或者其他界面直接會報500異常。是以說,我們在Controller中的方法,有時throws異常要慎用。

普遍的解決辦法:就是MVC模式以jsp作為表現層,控制器-模型-視圖,通過這種視圖跳轉的方式,郵箱注冊發送郵件是沒有任何問題的。如果用純HTML或純jsp,而不是通過視圖跳轉到jsp。

正常情況下,視圖應該是這樣的。

@RequestMapping("test")
public String test(){

  return "test";

}
      

  

通過上述這種方式跳轉jsp,而不是直接浏覽器輸入,例如這樣的,localhost:8080/test/test.jsp。當然這樣傳回也可以,但是不太符合MVC這種方式。

問題二:

Springmvc常見問題

描述:為什麼傳回重複的url呢?明明寫了正确的路徑。出現這種情況比較多的是由SpringMVC傳回JSON資料與前台進行異步互動。‘

問題原因:出現這個的問題的原因是因為我的url正常應該給前台傳回json資料,通常在springmvc中url要給前台傳回json,必須要定義一個ResponseBody,而我沒有定義這個,是以出現了這個異常。

解決辦法:

加上ResponseBody時,就能正常通路到JSON資料

如圖所示:

Springmvc常見問題

不過通常針對控制層而言,如果某個類基本傳回的是JSON,建議使用RestController

這樣一來不必每一個方法上都添加@ResponseBody

重複性添加該注解是一件很麻煩的事情,總而言之能偷懶就偷點懶。

下面貼一下RestController的源代碼:

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Controller;

/**
 * A convenience annotation that is itself annotated with
 * {@link Controller @Controller} and {@link ResponseBody @ResponseBody}.
 * <p>
 * Types that carry this annotation are treated as controllers where
 * {@link RequestMapping @RequestMapping} methods assume
 * {@link ResponseBody @ResponseBody} semantics by default.
 *
 * <p><b>NOTE:</b> {@code @RestController} is processed if an appropriate
 * {@code HandlerMapping}-{@code HandlerAdapter} pair is configured such as the
 * {@code RequestMappingHandlerMapping}-{@code RequestMappingHandlerAdapter}
 * pair which are the default in the MVC Java config and the MVC namespace.
 * In particular {@code @RestController} is not supported with the
 * {@code DefaultAnnotationHandlerMapping}-{@code AnnotationMethodHandlerAdapter}
 * pair both of which are also deprecated.
 *
 * @author Rossen Stoyanchev
 * @author Sam Brannen
 * @since 4.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     * @since 4.0.1
     */
    String value() default "";

}      

通常情況隻要在類上面加上諸如RequstMapping或者其他注解,一般都是全局的。

就如RestController源碼一樣,看它的注解就可以明白它同時具有Controller和ResponseBody兩個特性。

關于常用注解這裡貼個圖,便于回顧:

Springmvc常見問題
Springmvc常見問題
@Documented的作用:将此注解包含在 javadoc 中 ,它代表着此注解會被javadoc工具提取成文檔      

這裡在順便貼下Controller的源碼:

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Indicates that an annotated class is a "Controller" (e.g. a web controller).
 *
 * <p>This annotation serves as a specialization of {@link Component @Component},
 * allowing for implementation classes to be autodetected through classpath scanning.
 * It is typically used in combination with annotated handler methods based on the
 * {@link org.springframework.web.bind.annotation.RequestMapping} annotation.
 *
 * @author Arjen Poutsma
 * @author Juergen Hoeller
 * @since 2.5
 * @see Component
 * @see org.springframework.web.bind.annotation.RequestMapping
 * @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     */
    String value() default "";

}      

關于這段源碼,簡單的說其實關鍵就是上面的注解。

為什麼SpringMVC能夠通過@Controller+@RequestMapping得到正确的URL

首先不說@RequestMapping,針對如上源碼,之是以可以掃描到這個Conroller,關鍵就在@Component這個注解上。

這個注解可以了解為Struts2的action,對于struts2而言,每個action是一個執行個體,是以struts2是多例的。多例意味着,每一個對應的action,必須要在配置檔案中配置,是以我們可以看到随着項目的擴大,struts2對應的action相關的xml檔案會極速增加的。

而SpringMVC是單例,全局共享一個執行個體,是以通過@Component直接執行個體為Spring容器。

簡單的說,在我們初學spring時,要想将對象交給Spring進行管理,通常要配置如下的bean:

如下bean的作用主要是掃描com.eluzhu.rms.mapper的檔案下的資料通路層的代碼,通過該代碼就不用一個一個寫很多bean

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.eluzhu.rms.mapper"/>
    </bean>      

而@Component在此隐性建立bean,不需要你管理對象,而直接交給spring管理。

這樣對于效率的提高是非常有幫助的。

我之是以喜歡SpringMVC的最大原因,是因為簡單明了輕量化,struts2的話,當初學習的時候,感覺有不少難度,當然了,學習完後,用的多,習慣就好,但是每次比較煩躁的就是要增加一個類似于Controller作用的類,我都必須要配置一個struts2相關的xml檔案。時間久了,CV大法即可搞定,當後來接觸SpringMVC時,就發現我再也不想用struts2了。SpringMVC可以說是從Struts2演變而來并借助Spring的名氣。

當然了,在校學習Java的同學們,建議還是把Struts2學好,畢竟Struts2的更面向對象。而且涉及不少設計模式。學好Struts2,對了解SpringMVC非常有幫助。

問題三:SpringMVC的配置檔案關于注解配置,沒有配置好導緻本因傳回JSON資料,最後卻變成了XML。

Springmvc常見問題

解決辦法:在spring-mvc.xml配置檔案,添加如下内容即可解決:

<!-- FastJson注入 -->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <!-- 避免IE執行AJAX時,傳回JSON出現下載下傳檔案 -->
            <!-- FastJson -->
            <bean id="fastJsonHttpMessageConverter"
                  class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <!-- 這裡順序不能反,一定先寫text/html,不然ie下出現下載下傳提示 -->
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>