搜索词>>ref 耗时0.0130
  • vue ref 使用教程

    一.vue ref基本用法:本页面获取dom元素$title(t1.vue) <template>l; <div id="app">l; <div ref="testDom">l;11111</div>l; <button @click一.vue ref基本用法:本页面获取dom元素$title(t1.vue) <template> <div id="app"> <div ref="testDom">11111</div> <button @click="getTest">获取test节点</button> </div> </template> <script> export default { methods: { getTest() { console.log(this.$refs.testDom) } } }; </script>调试上面的代码:​vuejs ref获取本页面元素调试提示:ref除了可以获取本页面的dom元素,还可以拿到子组件中的data和去调用子组件中的方法二.vue ref获取子组件中的data$title(子组件) <template> <div> {{ msg }} </div> </template> <script> export default { data() { return { msg: "hello world" } } } </script>  $title(父组件) <template> <div id="app"> <HelloWorld ref="hello"/> <button @click="getHello">获取helloworld组件中的值</button> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld }, data() { return {} }, methods: { getHello() { console.log(this.$refs.hello.msg) } } }; </script> 调试:​三.vue ref调用子组件中的方法$title(子组件) <template> <div> </div> </template> <script> export default { methods: { open() { console.log("调用到了") } } } </script>  <template> <div id="app"> <HelloWorld ref="hello"/> <button @click="getHello">获取helloworld组件中的值</button> </div> </template> $title(父组件) <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld }, data() { return {} }, methods: { getHello() { this.$refs.hello.open(); } } }; </script> 调试:​四.vue ref子组件调用父组件方法$title(子组件) <template> <div> </div> </template> <script> export default { methods: { open() { console.log("调用了"); // 调用父组件方法 this.$emit("refreshData"); } } } </script>  $title(父组件) <template> <div id="app"> <HelloWorld ref="hello" @refreshData="getData"/> <button @click="getHello">获取helloworld组件中的值</button> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld }, data() { return {} }, methods: { getHello() { this.$refs.hello.open() }, getData() { console.log('111111') } } }; </script> 调试:​
  • spring boot项目中使用logback日志

    spring boot项目中使用logback日志,USING LOGBACK WITH SPRING BOOT ,Logback让一个优秀的企业应用程序的日志框架——它是快速,简单但强大的配置选项,有一个小的内存占用。我在介绍性的文章,介绍logback.Logback简介:一个企业日志框架。在Logback一系列的文章中,我讨论了如何使用XML配置Logback和Groovy。可选用的Logback配置:使用XML和Logback配置:使用Groovy.<h2>  引言</h2> <p>    Logback让一个优秀的企业应用程序的日志框架——它是快速,简单但强大的配置选项,有一个小的内存占用。我在介绍性的文章,介绍logback.Logback简介:一个企业日志框架。在Logback一系列的文章中,我讨论了如何使用XML配置Logback和Groovy。可选用的Logback配置:使用XML和Logback配置:使用Groovy.</p> <p>    在这篇文章中,我将讨论如何使用Logback spring boot 。虽然有许多Java日志记录选项,默认的 spring boot 选择使用Logback记录器。像许多东西在春天的引导,Logback默认配置合理的默认值。开箱即用的,spring boot使得Logback易于使用。</p> <h2>详细介绍</h2> <h4> </h4> <h3>创建日志记录器</h3> <p>    在以前的文章,我写过一篇关于如何用spring boot创建一个web应用。这里将会为这个web应用配置logback日志。这个应用包含  IndexController我们将添加日志记录代码。IndexController的代码是这样的。</p> <pre> <code class="language-java">package guru.springframework.controllers;     import guru.springframework.helpers.SpringLoggingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;   @Controller public class IndexController {     private final Logger logger = LoggerFactory.getLogger(this.getClass());     @RequestMapping("/")     String index(){         logger.debug("This is a debug message");         logger.info("This is an info message");         logger.warn("This is a warn message");         logger.error("This is an error message");         new SpringLoggingHelper().helpMethod();         return "index";     } }</code></pre> <p>让我们添加一个 SpringLoggingHelper类与应用程序日志代码。虽然这类不做任何事除了释放日志语句,它将帮助我们理解配置日志记录在不同的包中。这是SpringLoggingHelper 的代码:</p> <pre> <code class="language-java">package guru.springframework.helpers;     import org.slf4j.Logger; import org.slf4j.LoggerFactory;   public class SpringLoggingHelper {     private final Logger logger = LoggerFactory.getLogger(this.getClass());     public void helpMethod(){         logger.debug("This is a debug message");         logger.info("This is an info message");         logger.warn("This is a warn message");         logger.error("This is an error message");       } }</code></pre> <p>在上面的类中,我们写日志代码对SLF4J API。SLF4J是常用的外墙日志框架,如Java Util日志,Log4J 2和Logback。通过编写SLF4J,我们的代码仍然和Logback解耦,从而提供插件不同的日志框架的灵活性,以后如果需要。</p> <p>如果你想知道关于SLF4J和Logback依赖性,你不需要指定任何。spring boot包含它们。假设您正在使用Maven或Gradle管理你春天启动项目,必要的依赖关系是 spring boot 下的依赖关系的一部分。</p> <p>运行 SpringBootWebApplication主类。当应用程序启动时,从你的浏览器的URL访问它,<strong>http://localhost:8080</strong></p> <p>IntelliJ控制台的日志输出。</p> <p><img alt="在弹簧启动时使用默认配置记录输出" class="img-thumbnail" src="https://i2.wp.com/springframework.guru/wp-content/uploads/2016/04/logging_output_with_springboot-1024x266.png?resize=863%2C224&ssl=1" /></p> <p>我们还没有写任何Logback配置。输出的 IndexController和 SpringLoggingHelper从logback根记录器类。注意,调试消息没有得到记录。Logback默认情况下将日志消息调试水平。然而, spring boot 团队给我们提供了一个默认的配置在theSpring Logback启动默认Logback配置文件, 基地.xml。此外,Spring提供了提供两个预配置的输出源通过引导 控制台- - - - - -appender.xml和 文件- - - - - -appender.xml文件。的 基地.xml文件referencesboth。</p> <p>这是base.xml的代码,文件从spring-boot github获取。</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?>   <!-- Base logback configuration provided for compatibility with Spring Boot 1.1 -->   <included> <include resource="org/springframework/boot/logging/logback/defaults.xml" /> <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/> <include resource="org/springframework/boot/logging/logback/console-appender.xml" /> <include resource="org/springframework/boot/logging/logback/file-appender.xml" /> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> </root> </included></code></pre> <p>在这里您可以看到,通过将根记录器设置为INFO,Spring Boot已经覆盖了Logback的默认日志记录级别 ,这是上面示例中没有看到调试消息的原因。我们将在下一节中看到,在Spring Boot中更改日志级别非常简单。</p> <br /> 查看我的免费简介春季课程 <h4>通过Spring Boot的application.properties文件进行配置</h4> <p>在Spring Boot应用程序中,您可以外部化配置以在不同的环境中使用相同的应用程序代码。application.properties。属性文件可能是最受欢迎的几种不同的方法来外部化Spring Boot配置属性。在Spring Boot Web应用程序的默认结构中,可以找到application.properties。资源文件夹下的 属性文件。在application.properties中。属性文件,您可以定义Spring Boot的日志级别,应用程序记录器,Hibernate,Thymeleaf等。您还可以定义一个日志文件以将日志消息写入到控制台之外。</p> <p>下面是一个示例 应用。属性文件与日志配置。</p> <pre> <code>logging.level.org.springframework.web=INFO logging.level.guru.springframework.controllers=DEBUG logging.level.org.hibernate=ERROR logging.file=logs/spring-boot-logging.log</code></pre> <p><br /> 当您现在运行主类并访问应用程序时,将来自IndexController和 SpringLoggingHelper的日志消息 记录到控制台和logs / spring - boot - logging 。日志文件。<strong>注意</strong>:还有一个 日志记录。path属性来指定日志记录文件的路径。如果你使用它,Spring Boot会创建一个spring。日志文件在指定的路径。但是,您不能同时指定 日志记录。文件和 日志记录。路径属性在一起。如果完成,Spring Boot将忽略两者。</p> <p><img alt="使用application.properties启动Spring启动日志输出" class="img-thumbnail" src="https://i2.wp.com/springframework.guru/wp-content/uploads/2016/04/logging_output_with_application_properties-1024x486.png?resize=863%2C410&ssl=1" /></p> <p>在输出中,请注意IndexController的调试和更高级别的消息 已记录到控制台和文件中。这是因为在application.properties中。属性文件中,我们指定 DEBUG作为日志级 大师。springframework的。控制器包, IndexController是其中的一部分。由于我们没有明确配置 SpringLoggingHelper类,所以默认配置为 base 。使用了xml文件。因此,只有 记录了SpringLoggingHelper的INFO和更高级别的消息 。</p> <p>当您需要获取特定类或包的更详细的日志消息时,可以看到这是多么简单。</p> <h4>通过外部文件进行回溯配置</h4> <p>通过application.properties回溯配置。属性文件将足够用于许多Spring Boot应用程序。然而,大型企业应用程序可能会有更复杂的日志记录要求。如前所述,Logback通过<a href="https://springframework.guru/logback-configuration-using-xml/" rel="external nofollow" target="_blank">XML</a>和Groovy配置文件支持高级日志记录配置。</p> <p>在Spring Boot应用程序中,您可以将Logback XML配置文件指定为 logback 。xml或 logback - spring 。xml在项目类路径中。然而,Spring Boot团队建议使用<strong>-spring</strong>变体进行日志记录配置,   logback - spring 。XML优于  的logback 。xml。如果使用标准 的logback 。xml配置,Spring Boot可能无法完全控制日志的初始化。</p> <p>这是logback的代码 - spring 。xml文件。</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration>     <include resource="org/springframework/boot/logging/logback/base.xml"/>     <logger name="guru.springframework.controllers" level="WARN" additivity="false">         <appender-ref ref="CONSOLE"/>         <appender-ref ref="FILE"/>     </logger>     <logger name="guru.springframework.helpers" level="WARN" additivity="false">         <appender-ref ref="CONSOLE"/>         <appender-ref ref="FILE"/>     </logger> </configuration></code></pre> <p><br /> 通过更新的Spring Boot Logback配置,我们的日志输出现在如下所示:在上面的配置代码中,我们包括了 基础。第3行中的xml文件,请注意,我们没有配置任何appender。相反,我们依靠由Spring Boot提供的 CONSOLE和 FILE appender。</p> <p><img alt="记录Spring引导XML配置的输出" class="img-thumbnail" src="https://i0.wp.com/springframework.guru/wp-content/uploads/2016/04/logging_output_xml_configuration-1024x473.png?resize=863%2C399&ssl=1" /></p> <p><strong>注</strong>:Spring Boot要求 的logback - Spring。xml配置文件要在类路径上。但是,您可以将其存储在不同的位置,并使用日志记录指向它 。config属性在application.properties中。属性。</p> <h4>spring boot配置文件在日志记录中</h4> <p>在本地机器上开发时,通常将日志级别设置为 DEBUG。这将为您提供详细的日志消息供您开发使用。在生产时,它的典型设置将日志级别设置为 WARN或以上。这是为了避免在生产过程中运行时使用过多的调试信息和日志记录来填充日志。虽然日志记录非常有效,但仍然有成本。</p> <p>Spring Boot通过使用< springProfile >元素扩展用于回溯配置的Spring配置文件来解决这些要求 。使用你这个元素 的logback - spring。xml文件,您可以根据活动的spring boot配置文件选择性地包括或排除日志记录配置部分。</p> <p><strong>注意</strong>:在回弹配置中支持 < springProfile >可从SpringBoot 1.3.0.M2里程碑开始。</p> <p>以下是使用活动的Spring boot配置文件配置Logback的XML示例。</p> <p><br />  </p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration>     <include resource="org/springframework/boot/logging/logback/base.xml" />     <springProfile name="dev,staging">         <logger name="guru.springframework.controllers" level="DEBUG" additivity="false">             <appender-ref ref="CONSOLE" />         </logger>>     </springProfile>     <springProfile name="production">         <logger name="guru.springframework.controllers" level="WARN" additivity="false">             <appender-ref ref="FILE" />         </logger>     </springProfile> </configuration></code></pre> <p>要将配置文件传递给应用程序,请使用- Dspring运行 应用程序。档案。active = JVM参数。在上面的配置代码中,对于 dev和 staging配置文件,我们配置了上 师。springframework的。控制器记录器将DEBUG和更高级别的消息记录到 控制台。对于 生产配置文件,我们配置了相同的记录器来将WARN和更高级别的消息记录到 文件中。</p> <p>对于本地开发,在IntelliJ中,选择<strong>Run-> Edit Configurations</strong>,并在<strong>Run / Debug Configurations</strong>对话框中设置JVM参数,如下所示。</p> <p><img alt="设置用于登录IntelliJ的活动配置文件" class="img-thumbnail" src="https://i0.wp.com/springframework.guru/wp-content/uploads/2016/04/RunDebug_Configurations_Dialog.png?resize=755%2C261&ssl=1" /></p> <p>现在,当我们使用dev配置文件运行应用程序时 ,我们将看到以下日志输出。</p> <p><img alt="使用弹簧活动配置文件记录输出" class="img-thumbnail" src="https://i1.wp.com/springframework.guru/wp-content/uploads/2016/04/logging_output_springl_profile.png?resize=863%2C171&ssl=1" /></p> <p>在上面的输出中,观察IndexController的日志记录输出 。 根据dev配置文件的配置,DEBUG和更高的日志消息记录到控制台 。您可以使用生产配置文件重新启动应用程序, 以确保将 WARN和较高日志消息记录到该文件中。</p> <h4>配置文件的条件处理</h4> <p>Logback支持在Janino库的帮助下对配置文件进行条件处理。您可以使用配置文件中的 < if >, < then >和 <else >元素来定位多个环境。要执行条件处理,请将Janino依赖项添加到您的Maven POM中,像这样。</p> <pre> <code class="language-xml"><dependency>    <groupId>org.codehaus.janino</groupId>    <artifactId>janino</artifactId>    <version>2.7.8</version> </dependency></code></pre>   <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration>     <include resource="org/springframework/boot/logging/logback/base.xml" />     <springProfile name="dev,staging">         <logger name="guru.springframework.controllers" level="DEBUG" additivity="false">             <appender-ref ref="CONSOLE" />         </logger>>     </springProfile>     <springProfile name="production">     <logger name="guru.springframework.controllers" level="WARN" additivity="false">         <appender-ref ref="FILE" />     </logger>     </springProfile>     <if condition='property("spring.profiles.active").contains("dev")'>         <then>             <logger name="guru.springframework.helpers" level="DEBUG" additivity="false">                 <appender-ref ref="CONSOLE" />             </logger>         </then>         <else>             <logger name="guru.springframework.helpers" level="WARN" additivity="false">                 <appender-ref ref="FILE" />             </logger>         </else>     </if> </configuration></code></pre>   <p>完整的logback - spring。这是具有条件处理逻辑的xml文件。</p> <p> </p> <p>在上面的代码中,我们在< if >元素中指定了一个条件, 以检查当前活动的配置文件是否包含 dev。如果条件求 值为true,则< then >元素中的配置代码将 执行。在 < then >元素中,我们配置了 大师。springframework的。帮助人员将 DEBUG和更高级的消息记录到控制台。我们使用 < else >元素来配置记录器来将WARN和更高的消息记录到 日志文件中。所述 < 别的>元素执行用于比其它任何配置文件 dev的。</p> <p>当您使用生产配置文件运行应用程序 并进行访问时,两个记录器都会将 WARN和更高的消息记录到日志文件中,与此类似。<br /> <img alt="使用生产配置文件记录输出" class="img-thumbnail" src="https://i0.wp.com/springframework.guru/wp-content/uploads/2016/04/logging_output_production_profile.png?resize=642%2C319&ssl=1" /></p> <p>对于 dev配置文件,两个记录器都会将 DEBUG和更高级的消息记录到控制台,类似于此。<br /> <img alt="记录dev配置文件的输出" class="img-thumbnail" src="https://i2.wp.com/springframework.guru/wp-content/uploads/2016/04/logging_output_dev_profile.png?resize=863%2C222&ssl=1" /></p> <h4>logback自动扫描问题与spring boot</h4> <p>在的logback - spring。xml文件,您可以通过设置scan = “true”属性来启用配置的自动扫描 。启用自动扫描后,Logback扫描配置文件中的更改。对于任何更改,Logback自动重新配置它们。您可以通过将时间段传递给scanPeriod属性来指定扫描周期 ,其值以毫秒,秒,分钟或小时为单位指定。<br /> 例如,此代码告诉Logback扫描 logback - spring 。xml每10秒钟。</p> <pre> <code class="language-xml"><configuration debug="true" scan="true" scanPeriod="10 seconds" >   ... </configuration></code></pre>   <pre> <code>//Error on using auto-scan with springProfile   -ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:39 - no applicable action for [springProfile],   current ElementPath  is [[configuration][springProfile]]   //Error on using auto-scan with springProperty   -ERROR in ch.qos.logback.core.joran.spi.Interpreter@12:125 - no applicable action for [springProperty],     current ElementPath  is [[configuration][springProperty]]</code></pre>   <p>Spring Boot Logback的一个限制是使用 springProfile和 springProperty,设置自动扫描结果为错误。</p> <p>由于不兼容性问题而发生错误。Spring Boot使用 JoranConfigurator子类支持 springProfile和 springProperty。不幸的是,Logback的 ReconfigureOnChangeTask不提供挂接插件。</p> <h4>结论</h4> <p>Logback的流行趋势在于开源社区。许多受欢迎的开源项目使用Logback来记录日志需求。 <a href="https://camel.apache.org/" rel="external nofollow" target="_blank" title="阿帕奇骆驼">Apache Camel</a>,<a href="http://gradle.org/" rel="external nofollow" target="_blank" title="毕业">Gradle</a>和<a href="http://www.sonarqube.org/" rel="external nofollow" target="_blank">SonarQube</a>只是几个例子。</p> <p>回溯显然具有处理复杂企业应用程序登录需求的能力。所以,难怪Spring Boot团队为默认的日志记录实现选择了Logback。正如你在这篇文章中看到的,Spring Boot团队提供了与Logback的良好集成。开箱即用,Logback可以随Spring Boot一起使用。在这篇文章中,您已经看到,随着日志需求的发展,在spring boot中配置Logback是多么容易。<br /> <br /> 完整例子1:<br />  </p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。 debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="false" scanPeriod="60 seconds" debug="false"> <property name="filePath" value="/aos/logs/axschoolweb.log" /> <property name="fileNamePattern" value="/aos/logs/axschoolweb" /> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${filePath}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${fileNamePattern}.%d{yyyy-MM-dd}.log</fileNamePattern> </rollingPolicy> <encoder> <pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- level等级顺序:error>warn>info>debug。 --> <logger name="org.springframework" level="WARN"/> <logger name="org.springframework.web" level="DEBUG"/> <logger name="org.springframework.remoting" level="WARN"/> <logger name="org.springframework.scheduling.quartz" level="WARN"/> <logger name="org.springframework.data.jpa" level="WARN"/> <logger name="org.cometd" level="WARN"/> <logger name="ch.qos.logback" level="WARN"/> <logger name="jdbc.sqltiming" level="WARN"/> <logger name="com.leftso" level="DEBUG"><!--根据具体项目配置--> <appender-ref ref="rollingFile"/> </logger> <!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应, 要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --> <root level="DEBUG"> <appender-ref ref="console"/> <appender-ref ref="rollingFile"/> </root> </configuration></code></pre> <br /> <br /> 20171124更新=============================> <h3>logback配置打印mybaties sql日志</h3> <pre> <code class="language-xml"><logger name="net.xqlee.project.demo.dao" ><!--这里配置自己的dao(mybaties mapper接口)的包路径--> <level value="DEBUG"/> <appender-ref>console</appender-ref><!--指定一种或多种logback日志记录器--> </logger></code></pre> 如上代码片段所示,logback打开mybaties的sql打印日志需要创建一个logger并配置mybaties的dao所在包。然后将日志的等级调制DEBUG即可。日志的记录方式和其他logger一样可以配置多个。
  • log4j配置_log4j2的LevelRangeFilter使用详解_log4j使用

    log4j使用,log4j框架在java编程中还是比较常见的,这里将会讲解通过log4j2的LevelRangeFilter将不同级别log存放不同文件中。一.如何使用log4j本文将讲解如何使用log4j的LevelRangeFilter过滤器,如果LogEvent中的级别处于配置的最小和最大级别的范围内,则返回onMatch,否则返回onMismatch二.log4j LevelRangeFilter 使用例子在log4j2.xml配置文件中,我们使用LevelRangeFilter去过滤日志的等级通过以下的方式:所有info级别的日志将会保存到application-log4j-info.log 文件中所有debug级别的日志将会保存到application-log4j-debug.log 文件中所有error级别日志将会保存到application-log4j-error.log 文件中当然你也可以根据自己的项目进行对log4j的最低等级日志和最高日志等级进行配置,即配置log4j的minLevel和maxLevel属性<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" monitorInterval="30">       <Properties>         <Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} %p %m%n</Property>     </Properties>       <Appenders>           <Console name="Console" target="SYSTEM_OUT" follow="true">             <PatternLayout pattern="${LOG_PATTERN}"/>         </Console>                   <RollingFile name="debugLog" fileName="${sys:APP_LOG_ROOT}/application-debug.log"             filePattern="${sys:APP_LOG_ROOT}/application-debug-%d{yyyy-MM-dd}-%i.log">               <!-- Matches only DEBUG level -->             <LevelRangeFilter minLevel="DEBUG" maxLevel="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>               <PatternLayout pattern="${LOG_PATTERN}"/>             <Policies>                 <SizeBasedTriggeringPolicy size="19500KB" />             </Policies>             <DefaultRolloverStrategy max="10"/>         </RollingFile>                   <RollingFile name="infoLog" fileName="${sys:APP_LOG_ROOT}/application-info.log"             filePattern="${sys:APP_LOG_ROOT}/application-info-%d{yyyy-MM-dd}-%i.log" >               <!-- Matches only INFO level -->             <LevelRangeFilter minLevel="INFO" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>               <PatternLayout pattern="${LOG_PATTERN}"/>             <Policies>                 <SizeBasedTriggeringPolicy size="19500KB" />             </Policies>             <DefaultRolloverStrategy max="10"/>         </RollingFile>                   <RollingFile name="errorLog" fileName="${sys:APP_LOG_ROOT}/application-error.log"             filePattern="${sys:APP_LOG_ROOT}/application-error-%d{yyyy-MM-dd}-%i.log">               <!-- Matches only ERROR level -->             <LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>               <PatternLayout pattern="${LOG_PATTERN}"/>             <Policies>                 <SizeBasedTriggeringPolicy size="19500KB" />             </Policies>             <DefaultRolloverStrategy max="10"/>         </RollingFile>               </Appenders>       <Loggers>               <Logger name="com.leftso.app" additivity="false">             <AppenderRef ref="debugLog" />             <AppenderRef ref="infoLog"  />             <AppenderRef ref="errorLog" />             <AppenderRef ref="Console"  />         </Logger>                                  <Root level="all">             <AppenderRef ref="Console"/>         </Root>       </Loggers>   </Configuration>
  • spring boot 使用SLF4J Logging-Java编程

    Java编程之Spring Boot 使用SLF4J Logging,spring boot,SLF4J<h2>一、项目结构图</h2> <img alt="项目结构图" class="img-thumbnail" src="/assist/images/blog/b33c0281356d4650ac605ee4715f5600.png" /><br /> 默认情况下,SLF4j日志记录包含在Spring boot包中。<br /> <strong>application.properties</strong> <pre> <code>spring-boot-web-project$ mvn dependency:tree +... +- org.springframework.boot:spring-boot-starter-logging:jar:1.4.2.RELEASE:compile [INFO] | | | +- ch.qos.logback:logback-classic:jar:1.1.7:compile [INFO] | | | | \- ch.qos.logback:logback-core:jar:1.1.7:compile [INFO] | | | +- org.slf4j:jcl-over-slf4j:jar:1.7.21:compile [INFO] | | | +- org.slf4j:jul-to-slf4j:jar:1.7.21:compile [INFO] | | | \- org.slf4j:log4j-over-slf4j:jar:1.7.21:compile +...</code></pre> <p><strong>请注意</strong><br /> <em>查看这个Spring Boot Logback XML模板,了解默认的日志记录模式和配置。</em></p> <h2>二、配置文件</h2> <h3>2.1application.properties<br /> 要启用日志记录,创建一个应用程序。在资源文件夹的根目录下的属性文件。<br /> 日志记录。级别-定义日志级别,日志记录将输出到控制台。<br /> <strong>application.properties</strong></h3> <pre> <code>logging.level.org.springframework.web=ERROR logging.level.com.mkyong=DEBUG</code></pre> logging.file -定义日志文件,日志将输出到一个文件和控制台。<br /> <strong>application.properties</strong> <pre> <code>logging.level.org.springframework.web=ERROR logging.level.com.mkyong=DEBUG #output to a temp_folder/file logging.file=${java.io.tmpdir}/application.log #output to a file #logging.file=/Users/mkyong/application.log</code></pre> <code>logging.pattern</code> -定义一个定制的日志记录模式。<br /> <strong>application.properties</strong> <pre> <code>logging.level.org.springframework.web=ERROR logging.level.com.mkyong=DEBUG # Logging pattern for the console logging.pattern.console= "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" # Logging pattern for file logging.pattern.file= "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" logging.file=/Users/mkyong/application.log</code></pre> <h2><strong>application.yml</strong></h2> 这在YAML格式中是一样的<br /> <strong>application.yml</strong> <pre> <code>logging: level: org.springframework.web: ERROR com.mkyong: DEBUG pattern: console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" file: /Users/mkyong/application.log</code></pre> <h2><strong>Classic Logback.xml</strong></h2> 如果您不喜欢Spring引导日志模板,只需创建一个标准的logback。xml在资源文件夹的根目录或类路径的根目录下。这将覆盖Spring引导日志模板。<br /> <strong>logback.xml</strong> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="DEV_HOME" value="c:/logs" /> <appender name="FILE-AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${DEV_HOME}/debug.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern> %d{yyyy-MM-dd HH:mm:ss} - %msg%n </Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>${DEV_HOME}/archived/debug.%d{yyyy-MM-dd}.%i.log </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <logger name="com.mkyong" level="debug" additivity="false"> <appender-ref ref="FILE-AUDIT" /> </logger> <root level="error"> <appender-ref ref="FILE-AUDIT" /> </root> </configuration></code></pre> <h2>Spring Boot logging by Profile</h2> <p>请注意<br /> 阅读本文-概要文件的配置<br />  </p> <p>创建一个logback-spring。在类路径的根目录中使用xml,以利用Spring引导提供的模板特性。</p> <p>在以下的例子:</p> <p>如果配置文件为dev,则将日志记录到控制台和一个滚动文件。</p> <p>如果概要文件被戳了,则只记录到一个滚动文件。<br /> <strong>logback-spring.xml</strong><br />  </p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/> <springProfile name="dev"> <include resource="org/springframework/boot/logging/logback/console-appender.xml"/> <appender name="ROLLING-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.log</fileNamePattern> </rollingPolicy> </appender> <root level="ERROR"> <appender-ref ref="CONSOLE"/> <appender-ref ref="ROLLING-FILE"/> </root> </springProfile> <springProfile name="prod"> <appender name="ROLLING-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <root level="ERROR"> <appender-ref ref="ROLLING-FILE"/> </root> </springProfile> </configuration></code></pre> <br /> <strong>application.yml</strong> <pre> <code>spring: profiles: active: prod logging: level: ROOT: ERROR org.springframework: ERROR org.springframework.data: ERROR com.mkyong: INFO org.mongodb: ERROR file: /Users/mkyong/application.log</code></pre> 对于非web启动应用程序,您可以像这样覆盖日志文件输出: <pre> <code>$ java -Dlogging.file=/home/mkyong/app/logs/app.log -jar boot-app.jar</code></pre> <h2>Set Root Level</h2> <strong>application.properties</strong> <pre> <code># root logging level, warning : too much output logging.level.=DEBUG</code></pre> <strong>application.yml</strong> <pre> <code>logging: level: ROOT: DEBUG</code></pre> <br /> <a href="http://www.mkyong.com/wp-content/uploads/2017/01/spring-boot-web-slf4j-logging.zip" rel="external nofollow" target="_blank">下载演示demo</a>
  • SSH/SSM项目中如何集成thymeleaf

    SSH/SSM项目中如何集成thymeleaf?本文将讲解SSH/SSM项目中如何集成thymeleaf模板引擎      SSH/SSM项目中如何集成thymeleaf?本文将讲解SSH/SSM项目中如何集成thymeleaf模板引擎。为啥要用thymeleaf模板引擎呢?相信用过的小伙伴都知道使用它之后和前端打交道是否更容易了呢?接下来进入正题吧。<br />   <h2>1.添加必须依赖</h2> <pre> <code class="language-xml"><!--视图模板引擎--> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf</artifactId> <version>2.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>2.1.6.RELEASE</version> </dependency> </code></pre> <blockquote> <p>注意:如果是用3.X版本需要引入</p> </blockquote> <pre> <code class="language-xml"><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.0</version> </dependency> </code></pre> <blockquote> <p>版本大于2.5.0如果当前项目因其他依赖关系则放弃3.x使用2.x即可不依赖该库</p> </blockquote> <h2><br /> 2.配置</h2> SSH/SSM项目一般都有spring mvc的配置。修改spring mvc配置文件。添加以下内容 <pre> <code class="language-xml"><!--定义视图模板引擎--> <!--org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver--> <!--org.thymeleaf.templateresolver.ServletContextTemplateResolver--> <bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/templates/"/> <property name="suffix" value=".htm"/> <property name="templateMode" value="HTML5"/> <property name="cacheable" value="false"/><!-- 缓存--> <property name="characterEncoding" value="UTF-8"/><!--解决中文乱码--> </bean> <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver"/> </bean> <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine"/> <property name="order" value="2"/> <property name="viewNames" value="*_th"/> <property name="characterEncoding" value="UTF-8"/><!--解决中文乱码--> </bean> </code></pre> <p>注意,order必须小于JSP的大小默认不设置即可。设置一定要注意否则各种404问题。</p> <p>上面使用htm作为后缀是因为老项目将HTML后缀做过特殊统一处理。这里所以放弃HTML使用htm<br /> <br /> 添加layout扩展插件<br /> <br /> 1.添加依赖<br />  </p> <pre> <code class="language-xml"><dependency> <groupId>nz.net.ultraq.thymeleaf</groupId> <artifactId>thymeleaf-layout-dialect</artifactId> <version>1.4.0</version> </dependency> </code></pre> 2.修改spring mvc配置 <pre> <code class="language-xml"><bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine"/> <property name="order" value="2"/> <property name="viewNames" value="*_th"/> <property name="characterEncoding" value="UTF-8"/><!--解决中文乱码--> </bean> </code></pre>  
  • Quartz与Spring的整合-Quartz中的job如何自动注入spring容器托管的对象

    我们要达到这样的效果 <pre> <code class="language-java">public class CancelUnpaidOrderTask implements Job { @Autowired private AppOrderService orderService; @Override public void execute(JobExecutionContext ctx) throws JobExecutionException { ... } </code></pre> 但是Job对象的实例化过程是在Quartz中进行的,AppOrderService是在Spring容器当中的,那么如何将他们关联到一起呢。 好在Quartz提供了JobFactory接口,让我们可以自定义实现创建Job的逻辑。 <pre> <code class="language-java">public interface JobFactory { Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException; } </code></pre> 那么我们通过实现JobFactory 接口,在实例化Job以后,在通过ApplicationContext 将Job所需要的属性注入即可<br /> 在Spring与Quartz集成时 用到的是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类。源码如下,我们只看最关键的地方。 <pre> <code class="language-java">// Get Scheduler instance from SchedulerFactory. try { this.scheduler = createScheduler(schedulerFactory, this.schedulerName); populateSchedulerContext(); if (!this.jobFactorySet && !(this.scheduler instanceof RemoteScheduler)) { // Use AdaptableJobFactory as default for a local Scheduler, unless when // explicitly given a null value through the "jobFactory" bean property. this.jobFactory = new AdaptableJobFactory(); } if (this.jobFactory != null) { if (this.jobFactory instanceof SchedulerContextAware) { ((SchedulerContextAware) this.jobFactory).setSchedulerContext(this.scheduler.getContext()); } this.scheduler.setJobFactory(this.jobFactory); } } </code></pre> 如果我们不指定jobFactory,那么Spring就使用AdaptableJobFactory。我们在来看一下这个类的实现<br />   <pre> <code class="language-java">package org.springframework.scheduling.quartz; import java.lang.reflect.Method; import org.quartz.Job; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.spi.JobFactory; import org.quartz.spi.TriggerFiredBundle; import org.springframework.util.ReflectionUtils; public class AdaptableJobFactory implements JobFactory { public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException { return newJob(bundle); } public Job newJob(TriggerFiredBundle bundle) throws SchedulerException { try { Object jobObject = createJobInstance(bundle); return adaptJob(jobObject); } catch (Exception ex) { throw new SchedulerException("Job instantiation failed", ex); } } protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { // Reflectively adapting to differences between Quartz 1.x and Quartz 2.0... Method getJobDetail = bundle.getClass().getMethod("getJobDetail"); Object jobDetail = ReflectionUtils.invokeMethod(getJobDetail, bundle); Method getJobClass = jobDetail.getClass().getMethod("getJobClass"); Class jobClass = (Class) ReflectionUtils.invokeMethod(getJobClass, jobDetail); return jobClass.newInstance(); } protected Job adaptJob(Object jobObject) throws Exception { if (jobObject instanceof Job) { return (Job) jobObject; } else if (jobObject instanceof Runnable) { return new DelegatingJob((Runnable) jobObject); } else { throw new IllegalArgumentException("Unable to execute job class [" + jobObject.getClass().getName() + "]: only [org.quartz.Job] and [java.lang.Runnable] supported."); } } } </code></pre> 其他的我们都不管,我们就看红色的地方,这里是创建了一个Job,那我们就在这里去给Job的属性进行注入就可以了,让我们写一个类继承它,然后复写这个方法进行对Job的注入。 <pre> <code class="language-java">public class MyJobFactory extends AdaptableJobFactory { //这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴. @Autowired private AutowireCapableBeanFactory capableBeanFactory; protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //调用父类的方法 Object jobInstance = super.createJobInstance(bundle); //进行注入,这属于Spring的技术,不清楚的可以查看Spring的API. capableBeanFactory.autowireBean(jobInstance); return jobInstance; } } </code></pre> 接下来把他配置到Spring当中去 <pre> <code class="language-xml"><bean id="jobFactory" class="com.gary.operation.jobdemo.demo1.MyJobFactory"></bean></code></pre> 然后在把org.springframework.scheduling.quartz.SchedulerFactoryBean的jobFactory设置成我们自己的。 <pre> <code class="language-xml"><bean name="MyScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">   <!-- 其他属性省略 -->   <property name="jobFactory" ref="jobFactory"></property> </bean> </code></pre> 这样就完成了Spring对Job的注入功能,其实很简单,原理就是在我们扩展JobFactory创建job的方法,在创建完Job以后进行属性注入。<br />  
  • Spring Security 配置多个Authentication Providers认证器

    Spring Security 配置多个Authentication Providers认证器Spring Security 配置多个Authentication Providers认证器 <h2><strong>1.概述</strong></h2> 在这篇快速文章中,我们将重点介绍如何使用多种机制在Spring Security中对用户进行身份验证。<br /> 我们将通过配置多个身份验证提供程序来完成此操作<br />   <h2><strong>2. Authentication Providers</strong></h2> AuthenticationProvider是从特定存储库(如数据库,LDAP,自定义第三方来源等)获取用户信息的抽象概念。 它使用获取的用户信息来验证提供的凭证。<br /> <br /> 简而言之,当定义多个身份验证提供程序时,提供程序将按其声明的顺序进行查询。<br /> <br /> 为了快速演示,我们将配置两个身份验证提供程序 - 一个定制身份验证提供程序和一个内存身份验证提供程序 <h2><strong>3. Maven 依赖</strong></h2> 我们首先在我们的Web应用程序中添加必要的Spring Security依赖项: <pre> <code class="language-xml"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency></code></pre> 没有Spring Boot: <pre> <code class="language-xml"><dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.0.4.RELEASE</version> </dependency></code></pre> <h2><strong>4. 自定义 Authentication Provider</strong></h2> 现在让我们通过实现AuthneticationProvider接口来创建一个自定义身份验证提供程序。<br /> <br /> 我们将实施验证方法 - 它将尝试验证。 输入的Authentication对象包含用户提供的用户名和密码凭证。<br /> <br /> 如果身份验证成功,则身份验证方法会返回完全填充的身份验证对象。 如果身份验证失败,则会抛出AuthenticationException类型的异常:<br />   <pre> <code class="language-java">@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName(); String password = auth.getCredentials() .toString(); if ("externaluser".equals(username) && "pass".equals(password)) { return new UsernamePasswordAuthenticationToken (username, password, Collections.emptyList()); } else { throw new BadCredentialsException("External system authentication failed"); } } @Override public boolean supports(Class<?> auth) { return auth.equals(UsernamePasswordAuthenticationToken.class); } }</code></pre> 当然,这是我们这里例子的一个简单实现。 <h2><strong>5. 配置Multiple Authentication Providers</strong></h2> 现在让我们将CustomAuthenticationProvider和一个内存中验证提供程序添加到我们的Spring Security配置中。 <h3><strong>5.1. Java Configuration</strong></h3> 在我们的配置类中,现在让我们使用AuthenticationManagerBuilder创建和添加身份验证提供程序。<br /> <br /> 首先,通过使用inMemoryAuthentication(),使用CustomAuthenticationProvider,然后使用内存认证提供程序。<br /> <br /> 我们还确保访问URL模式“/ api / **”需要进行身份验证: <pre> <code class="language-java">@EnableWebSecurity public class MultipleAuthProvidersSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired CustomAuthenticationProvider customAuthProvider; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthProvider); auth.inMemoryAuthentication() .withUser("memuser") .password(encoder().encode("pass")) .roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic() .and() .authorizeRequests() .antMatchers("/api/**") .authenticated(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }</code></pre>   <h3><strong>5.2. XML Configuration</strong></h3> 或者,如果我们想使用XML配置而不是Java配置: <pre> <code class="language-xml"><security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="memuser" password="pass" authorities="ROLE_USER" /> </security:user-service> </security:authentication-provider> <security:authentication-provider ref="customAuthenticationProvider" /> </security:authentication-manager> <security:http> <security:http-basic /> <security:intercept-url pattern="/api/**" access="isAuthenticated()" /> </security:http></code></pre> <h2><strong>6. 应用Application</strong></h2> 接下来,让我们创建一个由我们的两个身份验证提供程序保护的简单REST端点。<br /> <br /> 要访问此端点,必须提供有效的用户名和密码。 我们的身份验证提供程序将验证凭据并确定是否允许访问: <pre> <code class="language-java">@RestController public class MultipleAuthController { @GetMapping("/api/ping") public String getPing() { return "OK"; } }</code></pre>   <h2><strong>7. 测试</strong></h2> 最后,我们现在测试对安全应用程序的访问权限。 只有提供有效凭证时才允许访问: <pre> <code class="language-java">@Autowired private TestRestTemplate restTemplate; @Test public void givenMemUsers_whenGetPingWithValidUser_thenOk() { ResponseEntity<String> result = makeRestCallToGetPing("memuser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenExternalUsers_whenGetPingWithValidUser_thenOK() { ResponseEntity<String> result = makeRestCallToGetPing("externaluser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenAuthProviders_whenGetPingWithNoCred_then401() { ResponseEntity<String> result = makeRestCallToGetPing(); assertThat(result.getStatusCodeValue()).isEqualTo(401); } @Test public void givenAuthProviders_whenGetPingWithBadCred_then401() { ResponseEntity<String> result = makeRestCallToGetPing("user", "bad_password"); assertThat(result.getStatusCodeValue()).isEqualTo(401); } private ResponseEntity<String> makeRestCallToGetPing(String username, String password) { return restTemplate.withBasicAuth(username, password) .getForEntity("/api/ping", String.class, Collections.emptyMap()); } private ResponseEntity<String> makeRestCallToGetPing() { return restTemplate .getForEntity("/api/ping", String.class, Collections.emptyMap()); }</code></pre> <h2><strong>8. 总结</strong></h2> 在本快速教程中,我们已经看到了如何在Spring Security中配置多个身份验证提供程序。 我们使用自定义身份验证提供程序和内存身份验证提供程序确保了一个简单应用程序。<br /> <br /> 我们还编写了测试,以验证对我们应用程序的访问需要至少有一个身份验证提供程序可以验证的凭据。
  • springMVC4+Spring4+Mybaties3项目整合简单例子

    本文章主要简单讲解目前流行的springMVC4+Spring4+Mybaties3(即SSM)框架整合<h2>一.创建一个web的maven项目</h2> 项目完整结构图:<br /> <img alt="项目结构" class="img-thumbnail" src="/assist/images/blog/27a2fcf7-752b-47b6-800a-99fad6608711.png" style="height:911px; width:457px" /> <h2> 二.相关文件内容</h2> <br />  1.pom.xml <pre> <code class="language-xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xqlee.dev.project.ssm</groupId> <artifactId>demo-ssm</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>demo-ssm Maven Webapp</name> <url>http://maven.apache.org</url> <profiles> <profile> <id>jdk-1.8</id> <!-- 另外一种激活方式 --> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> <com.fasterxml.jackson.jaxrs.version>2.4.1</com.fasterxml.jackson.jaxrs.version> </properties> </profile> </profiles> <!-- 属性版本 --> <properties> <junit.version>4.12</junit.version> <spring.version>4.1.7.RELEASE</spring.version> <mybatis.version>3.2.6</mybatis.version> <org.slf4j.version>1.7.2</org.slf4j.version> <mysql.driver.version>5.1.32</mysql.driver.version> <com.fasterxml.jackson.jaxrs.version>2.4.1</com.fasterxml.jackson.jaxrs.version> <commons-fileupload.version>1.3.1</commons-fileupload.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <!-- 测试所需 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- spring core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <!-- mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!-- mybatis/spring包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.2</version> </dependency> <!-- MySQL数据库驱动 导入 start --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.driver.version}</version> </dependency> <!-- MySQL数据库驱动 导入 end --> <!-- 导入dbcp的jar包,数据库连接池 --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <!-- el 标签库 --> <!-- standard.jar --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> </dependency> <!-- /el 标签库 --> <!-- 处理json --> <dependency> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-xml-provider</artifactId> <version>${com.fasterxml.jackson.jaxrs.version}</version> </dependency> <!-- 文件上传下载 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>${commons-fileupload.version}</version> </dependency> <!-- slf4j 和 log4j合用的Maven配置 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${org.slf4j.version}</version> </dependency> </dependencies> <build> <finalName>demo-ssm</finalName> </build> </project> </code></pre> <br /> 2.整合spring mybaties spring-mybatis.xml <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> <!-- 初始化连接大小 --> <property name="initialSize" value="${initialSize}"></property> <!-- 连接池最大数量 --> <property name="maxActive" value="${maxActive}"></property> <!-- 连接池最大空闲 --> <property name="maxIdle" value="${maxIdle}"></property> <!-- 连接池最小空闲 --> <property name="minIdle" value="${minIdle}"></property> <!-- 获取连接最大等待时间 --> <property name="maxWait" value="${maxWait}"></property> </bean> <!-- ========================================针对myBatis的配置项============================== --> <!-- 配置sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 实例化sqlSessionFactory时需要使用上述配置好的数据源以及SQL映射文件 --> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描me/gacl/mapping/目录下的所有SQL映射的xml文件, 省掉Configuration.xml里的手工配置 value="classpath:com/mapper/*.xml"指的是classpath(类路径)下com.mapping包中的所有xml文件 UserMapper.xml位于com.mapping包下,这样UserMapper.xml就可以被自动扫描 --> <property name="mapperLocations" value="classpath:com/xqlee/dev/project/ssm/mapping/*.xml" /> <!-- 加载mybatis.cfg.xml文件 --> <property name="configLocation" value="classpath:mybatis.cfg.xml"></property> </bean> <!-- 配置扫描器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 扫描com.dao这个包以及它的子包下的所有映射接口类 --> <property name="basePackage" value="com.xqlee.dev.project.ssm.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> <!-- ========================================分隔线========================================= --> <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> </beans> </code></pre> <br /> 3.mybatis.cfg.xml <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org/DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration> </configuration></code></pre> <br /> 4.jdbc.properties <pre> <code>driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/test username=root password=root initialSize=0 maxActive=20 maxIdle=20 minIdle=1 maxWait=60000</code></pre> <br /> 5.log4j.properties <pre> <code>log4j.rootLogger=INFO,Console,File log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.Target=System.out log4j.appender.Console.layout = org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n log4j.appender.File = org.apache.log4j.RollingFileAppender log4j.appender.File.File = logs/ssm.log log4j.appender.File.MaxFileSize = 10MB log4j.appender.File.Threshold = ALL log4j.appender.File.layout = org.apache.log4j.PatternLayout log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c]%m%n </code></pre> <br /> 6.spring-context.xml,spring容器启动配置 <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd "> <context:annotation-config /> <import resource="classpath:spring-mybatis.xml"/> <import resource="classpath:spring-mvc.xml"/> </beans></code></pre> <br /> 7.spring-mvc.xml,springMVC配置类 <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd "> <!-- 自动扫描controller包下所有 --> <context:component-scan base-package="com.xqlee.dev.project.ssm" /> <!-- 注解驱动 --> <mvc:annotation-driven /> <mvc:default-servlet-handler /> <!-- 资源管理不拦截 --> <mvc:resources location="/resources/" mapping="/resources/**" /> <mvc:resources location="/upload/" mapping="/upload/**" /> <!-- 内部资源视图解析器 prefix + logicName + suffix /WEB-INF/jsps/ + index + .jsp --> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/pages/" /> <!-- 后缀 --> <property name="suffix" value="" /> </bean> <!-- 处理在controller中使用注解@ResponseBody标签返回JSON数据 Start --> <!-- 注意[由于我在pom.xml引入的是2.4.1版本]:所以class=org.springframework.http.converter.json.MappingJackson2HttpMessageConverter --> <!-- [如果pom.xml引入的是1.xx版本]class=org.springframework.http.converter.json.MappingJacksonHttpMessageConverter --> <bean id="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> <value>text/json;charset=UTF-8</value> <value>application/json;charset=UTF-8</value> </list> </property> </bean> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="mappingJackson2HttpMessageConverter" /> </list> </property> </bean> <!-- JSON数据处理 End --> <!-- 上传图片/文件需要配置 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="-1" /><!-- -1表示没有限制 --> <property name="maxInMemorySize" value="4096" /> </bean> </beans></code></pre> <br /> 8.User.java <pre> <code class="language-java">package com.xqlee.dev.project.ssm.pojo; public class User { private int id; private String name; private String password; private int age; /** * @return the id */ public int getId() { return id; } /** * @param id * the id to set */ public void setId(int id) { this.id = id; } /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * @return the password */ public String getPassword() { return password; } /** * @param password * the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the age */ public int getAge() { return age; } /** * @param age * the age to set */ public void setAge(int age) { this.age = age; } } </code></pre> 9.UserMapper.java <pre> <code class="language-java">package com.xqlee.dev.project.ssm.dao; import java.util.List; import org.apache.ibatis.annotations.Param; import com.xqlee.dev.project.ssm.pojo.User; public interface UserMapper { User findById(@Param("id")int id); List<User> findList(@Param("name")String name); } </code></pre> 10.UserMapper.xml <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.xqlee.dev.project.ssm.dao.UserMapper"> <resultMap id="BaseMap" type="com.xqlee.dev.project.ssm.pojo.User"> <id column="id" property="id" jdbcType="INTEGER" /><!-- 注意这里的jdbcType参考mybaties官方文档 --> <result column="name" property="name" jdbcType="VARCHAR" /> </resultMap> <!-- mapper代理开发方式,namespace的值必须是对应接口的全类名 --> <select id="findById" parameterType="int" resultType="com.xqlee.dev.project.ssm.pojo.User"> select * from t_user where id = #{id} </select> <select id="findList" resultMap="BaseMap" parameterType="java.util.Map"> select * from t_user u where 1=1 <if test="name != null"> and u.name like CONCAT('%',#{name,jdbcType=VARCHAR},'%') </if> </select> </mapper> </code></pre> 11.UserService.java <pre> <code class="language-java">package com.xqlee.dev.project.ssm.service; import java.util.List; import com.xqlee.dev.project.ssm.pojo.User; public interface UserService { User getById(int id); List<User> findList(String name); } </code></pre> 12.UserServiceImp.java <pre> <code class="language-java">package com.xqlee.dev.project.ssm.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.xqlee.dev.project.ssm.dao.UserMapper; import com.xqlee.dev.project.ssm.pojo.User; @Service("userService") public class UserServiceImp implements UserService { @Autowired UserMapper userMapper; @Override public User getById(int id) { return userMapper.findById(id); } @Override public List<User> findList(String name) { // TODO Auto-generated method stub return userMapper.findList(name); } } </code></pre> <br /> 13.Test.java <pre> <code class="language-java">package com.xqlee.dev.project.ssm; import java.util.List; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.xqlee.dev.project.ssm.pojo.User; import com.xqlee.dev.project.ssm.service.UserService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:spring-context.xml" }) public class Test { @Autowired UserService userService; @org.junit.Test public void test1() { User user = userService.getById(1); System.out.println(user.getName()); List<User> users=userService.findList(""); for(User u:users){ System.out.println("name:"+u.getName()+" id:"+u.getId()); } } } </code></pre> 14.测试表以及测试数据 <pre> <code class="language-sql">DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(40) NOT NULL, `password` varchar(255) NOT NULL, `age` int(4) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; /*Data for the table `user_t` */ insert into `t_user`(`id`,`name`,`password`,`age`) values (1,'测试1','123456',24); insert into `t_user`(`id`,`name`,`password`,`age`) values (2,'测试2','123456',25); insert into `t_user`(`id`,`name`,`password`,`age`) values (3,'测试3','123456',26); </code></pre> 15.执行测试:<br /> <img alt="测试结果" class="img-thumbnail" src="/assist/images/blog/a9af66c8-3278-4c69-a287-1019e80bbf72.jpg" style="height:515px; width:972px" /><br /> <br /> 看到上图的结果,表示spring+mybaties已经完成整合,接下来将springMVC整合进来就OK了。<br /> <br /> 16.配置web.xml,整合上面的springMVC+spring+mybaties <pre> <code class="language-xml"><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>Archetype Created Web Application</display-name> <!-- 字符集处理 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- spring 核心配置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring-context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置缓存清除监听器,负责处理由 JavaBean Introspector 功能而引起的缓存泄露 --> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <!-- springMVC配置 --> <servlet> <servlet-name>springMVCSerlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVCSerlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 添加下面容器,防止同一个服务器部署多个项目web.root冲突 --> <context-param> <param-name>webAppRootKey</param-name> <param-value>springMVC4</param-value> </context-param> <!-- session timeout --> <session-config> <!-- 分钟 --> <session-timeout>60</session-timeout> </session-config> <!-- log4j配置 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:/log4j.properties</param-value> </context-param> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>60000</param-value> </context-param> <!--添加监听 --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!-- /log4j配置 --> <!-- welcome page --> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- session copy --> <distributable /> </web-app></code></pre> 17.WEB-INF目录下创建pages目录,并且在里面创建一个hello.jsp<br /> hello.jsp: <pre> <code class="language-html"><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>hello</title> </head> <body> Hello ,<B>${name }</B> </body> </html></code></pre> 18.创建UserController.java <pre> <code class="language-java">package com.xqlee.dev.project.ssm.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import com.xqlee.dev.project.ssm.pojo.User; import com.xqlee.dev.project.ssm.service.UserService; @Controller public class UserController { @Autowired UserService userService; @RequestMapping("/hello/{id}.html") public String hello(@PathVariable(value="id") int id, Model model) { User user = userService.getById(id); model.addAttribute("name", user.getName()); return "hello.jsp"; } } </code></pre> <br /> 上面内容创建完成后,将项目添加到tomcat或者其他容器中,启动项目<br /> <img alt="tomcat启动日志" class="img-thumbnail" src="/assist/images/blog/fab24f7c-8095-48cd-8b7c-8c6a27dd1f0c.png" style="height:684px; width:871px" /><br /> <br /> 上图是tomcat的启动日志,圈出来的是我们在UserController写的一个访问类<br /> 下面在浏览器中输入地址:<br /> <img alt="浏览器" class="img-thumbnail" src="/assist/images/blog/e65e25b3-a9f8-4608-acc8-1481c12f20f4.png" style="height:323px; width:512px" /><br /> 说明:访问地址 /hello/1.html<br /> 1表示后台control中接受到的用户id的参数值。<br /> 之所以页面显示的测试1,是因为前面我们已经将测试数据导入数据库,id等于1的用户刚好名称叫测试1<br /> 至此SSM三大框架整合基础完成。
  • java常用框架SpringMVC3/4入门教程

    SpringMVC框架是一个java里面非常轻量级的mvc框架之一,与spring框架同源,整合方便快捷.java常用框架SpringMVC3/4入门教程 <p>1SpringMVC3</p> <p>1.1项目结构图</p> <img alt="java常用框架SpringMVC3/4入门教程" src="/assist/images/blog/50f775fc-8470-4e98-bab8-a9195d8d2671.png" style="height:527px; width:313px" /> <p>1.2Pom.xml</p> <pre> <code class="language-xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>seven.org</groupId>    <artifactId>springmvc3</artifactId>    <packaging>war</packaging>    <version>0.0.1-SNAPSHOT</version>    <name>springmvc3 Maven Webapp</name>    <url>http://maven.apache.org</url>    <properties>       <junit.version>4.12</junit.version>       <spring.version>3.2.2.RELEASE</spring.version>       <org.codehaus.jackson.version>1.9.13</org.codehaus.jackson.version>       <commons-fileupload.version>1.3.1</commons-fileupload.version>    </properties>    <dependencies>       <dependency>          <!-- test -->          <groupId>junit</groupId>          <artifactId>junit</artifactId>          <version>${junit.version}</version>          <scope>test</scope>       </dependency>         <!-- spring framework start -->       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-core</artifactId>          <version>${spring.version}</version>       </dependency>       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-context</artifactId>          <version>${spring.version}</version>       </dependency>       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-web</artifactId>          <version>${spring.version}</version>       </dependency>       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-webmvc</artifactId>          <version>${spring.version}</version>       </dependency>       <!-- spring framework end -->         <!-- 为SpringMVC提供json数据类型支持 -->         <!-- 注意,新版的 jackson-core-asl已经升级为Group:com.fasterxml.jackson.core|Artifact:jackson-core在SpringMVC4中需要使用新版 -->       <dependency>          <groupId>org.codehaus.jackson</groupId>          <artifactId>jackson-core-asl</artifactId>          <version>${org.codehaus.jackson.version}</version>       </dependency>       <dependency>          <groupId>org.codehaus.jackson</groupId>          <artifactId>jackson-mapper-asl</artifactId>          <version>${org.codehaus.jackson.version}</version>       </dependency>         <!-- el 标签库 -->       <!-- standard.jar -->       <dependency>          <groupId>taglibs</groupId>          <artifactId>standard</artifactId>          <version>1.1.2</version>       </dependency>       <!-- JSTL -->       <dependency>          <groupId>javax.servlet</groupId>          <artifactId>jstl</artifactId>          <version>1.1.2</version>       </dependency>       <!-- /el 标签库 -->         <!-- 文件上传下载 -->       <dependency>          <groupId>commons-fileupload</groupId>          <artifactId>commons-fileupload</artifactId>          <version>${commons-fileupload.version}</version>       </dependency>         <!-- slf4j 和 log4j合用的Maven配置 -->       <dependency>          <groupId>org.slf4j</groupId>          <artifactId>slf4j-log4j12</artifactId>          <version>1.7.2</version>       </dependency>      </dependencies>    <build>       <finalName>springmvc3</finalName>    </build> </project></code></pre>   <p>1.3web.xml</p> <pre> <code class="language-xml"><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"    version="3.0">    <display-name>Archetype Created Web Application</display-name>      <!-- 字符集处理 -->    <filter>       <filter-name>CharacterEncodingFilter</filter-name>       <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>       <init-param>          <param-name>encoding</param-name>          <param-value>utf-8</param-value>       </init-param>    </filter>    <filter-mapping>       <filter-name>CharacterEncodingFilter</filter-name>       <url-pattern>/*</url-pattern>    </filter-mapping>        <!-- spring 配置 -->    <context-param>       <param-name>contextConfigLocation</param-name>       <param-value>classpath:/cfg/spring/spring-beans.xml</param-value>    </context-param>    <listener>       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>      <!-- 配置缓存清除监听器,负责处理由 JavaBean Introspector 功能而引起的缓存泄露 -->    <listener>       <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>    </listener>        <!-- springMVC配置 -->    <servlet>       <servlet-name>springMVCSerlet</servlet-name>       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>       <init-param>          <param-name>contextConfigLocation</param-name>          <param-value>classpath:/cfg/spring/spring-servlet.xml</param-value>       </init-param>       <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>       <servlet-name>springMVCSerlet</servlet-name>       <url-pattern>/</url-pattern>    </servlet-mapping>      <!-- 添加下面容器,防止同一个服务器部署多个项目web.root冲突 -->    <context-param>       <param-name>webAppRootKey</param-name>       <param-value>springMVC3</param-value>    </context-param>        <!-- log4j配置 -->    <context-param>       <param-name>log4jConfigLocation</param-name>       <param-value>classpath:/cfg/log/Log4j.properties</param-value>    </context-param>    <context-param>       <param-name>log4jRefreshInterval</param-name>       <param-value>60000</param-value>    </context-param>      <!-- session timeout -->    <session-config>       <!-- 分钟 -->       <session-timeout>60</session-timeout>    </session-config>      <!-- welcome page -->    <welcome-file-list>       <welcome-file>index.html</welcome-file>       <welcome-file>index.jsp</welcome-file>    </welcome-file-list>      <!-- session copy -->    <distributable /> </web-app></code></pre>   <p>1.4spring-servlet.xml</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd             http://www.springframework.org/schema/mvc             http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd             http://www.springframework.org/schema/context             http://www.springframework.org/schema/context/spring-context-3.2.xsd ">      <!-- 自动扫描包 -->    <context:component-scan base-package="com" />      <!-- 注解驱动 -->    <mvc:annotation-driven />    <mvc:default-servlet-handler />    <!-- 资源管理不拦截 -->    <mvc:resources location="/resources/" mapping="/resources/**" />    <mvc:resources location="/upload/" mapping="/upload/**" />      <!-- 内部资源视图解析器 prefix + logicName + suffix /WEB-INF/jsps/ + index + .jsp -->    <bean id="internalResourceViewResolver"       class="org.springframework.web.servlet.view.InternalResourceViewResolver">       <!-- 前缀 -->       <property name="prefix" value="/WEB-INF/pages/" />       <!-- 后缀 -->       <property name="suffix" value="" />    </bean>        <!-- 上传图片/文件需要配置 -->    <bean id="multipartResolver"       class="org.springframework.web.multipart.commons.CommonsMultipartResolver">       <property name="maxUploadSize" value="104857600" />       <property name="maxInMemorySize" value="4096" />    </bean>        <!-- 配置JSON支持 start -->    <bean id="mappingJacksonHttpMessageConverter"    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">       <property name="supportedMediaTypes">          <list>             <!-- 处理返回的json数据的编码,默认是ISO-88859-1 -->             <value>text/html;charset=UTF-8</value>          </list>       </property>    </bean>    <bean    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">       <!-- messageConverters属性中加入 mappingJacksonHttpMessageConverter用来处理json数据类行 -->       <property name="messageConverters">          <list>             <ref bean="mappingJacksonHttpMessageConverter" />          </list>       </property>    </bean>    <!-- 配置JSON支持 end -->     </beans></code></pre> <br /> 1.5spring-beans.xml <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa"    xsi:schemaLocation="http://www.springframework.org/schema/beans                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd             http://www.springframework.org/schema/mvc             http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd               http://www.springframework.org/schema/aop             http://www.springframework.org/schema/aop/spring-aop-3.2.xsd             http://www.springframework.org/schema/context             http://www.springframework.org/schema/context/spring-context-3.2.xsd             http://www.springframework.org/schema/tx             http://www.springframework.org/schema/tx/spring-tx-3.2.xsd             http://www.springframework.org/schema/data/jpa             http://www.springframework.org/schema/data/jpa/spring-jpa.xsd ">    <context:annotation-config />    <!-- 启动自动扫描该包下所有的注解(如@controller) -->    <context:component-scan base-package="com" />   </beans>  </code></pre>   <p>1.6Log4j配置文件</p> <pre> <code>#defind the rooeLogger ,the rootlogger min level is INFO,and two way to output log log4j.rootLogger = INFO,FILE,CONSOLE,DATABASE   #---------------------------------------------------------------------- #defind the FILE as file everyday                                     | #---------------------------------------------------------------------- log4j.appender.FILE = org.apache.log4j.DailyRollingFileAppender   #the log min level set as INFO log4j.appender.FILE.Threshold=INFO   #log file encoding set UTF-8 log4j.appender.FILE.encoding=UTF-8   #log file path log4j.appender.FILE.File=/home/tomcat/log/springmvc3/springmvc3   #log file name append log4j.appender.FILE.DatePattern='_'yyyy-MM-dd'.log'   #Immediate write the log is true log4j.appender.FILE.ImmediateFlush=true   #the layout of the log log4j.appender.FILE.layout=org.apache.log4j.PatternLayout   #the detail layout of log  in the log file log4j.appender.FILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} Springmvc3 %-5p [%c:%L] | %m%n   #------------------------------------------------------------------------- #this use the 'org.apache.log4j.ConsoleAppender' to output in the Console| #------------------------------------------------------------------------- log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender   #output min level is INFO log4j.appender.Threshold=INFO   #the output target is Console log4j.appender.CONSOLE.Target=System.out   #the layout of the log log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} springmvc3 %-5p | %m%n   #---------------------------------------------------------------------------- #insert the log into database                                               | #---------------------------------------------------------------------------- log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender #The jdbc url log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/springmvc3 #The jdbc driver log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver #DB user log4j.appender.DATABASE.user=root #DB password log4j.appender.DATABASE.password=root #sql log4j.appender.DATABASE.sql=INSERT INTO zhl_log (operationTime,logLevel,logClass,logDetail)  VALUES ("%d{yyyy-MM-dd HH:mm:ss}", "%-5p","%F:%L", "%m") #layout log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout #layout detail log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</code></pre> <br /> 1.7测试vo <pre> <code class="language-java">package com.xqlee.springmvc.vo;   /**  *  *  * <pre>  * @功能说明 [测试bean]  * @其他说明 [暂无]  * @文件编码 [UTF-8]  * @所属包名 [com.xqlee.springmvc.vo]  * @项目名称 [cdws]  * @创建日期 []  * @创建人员 [lxq]  * @最后修改 []  * @修改说明 [暂无更新]  * @修改人员 [lxq]  * @公司组织 [org]  * @版本说明 [v 1.0]  *  * </pre>  */ public class Tobject {      private String id;    private String name;    private String num;      public Tobject(String id, String name, String num) {       this.id = id;       this.name = name;       this.num = num;    }      public String getId() {       return id;    }      public void setId(String id) {       this.id = id;    }      public String getName() {       return name;    }      public void setName(String name) {       this.name = name;    }      public String getNum() {       return num;    }      public void setNum(String num) {       this.num = num;    }   }</code></pre> <br /> 1.8测试controller <pre> <code class="language-java">package com.xqlee.springmvc.controller;   import java.util.Vector;   import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;   import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;   import com.xqlee.springmvc.vo.Tobject;   /**  *  *  * <pre>  * @功能说明 [测试类]  * @其他说明 [暂无]  * @文件编码 [UTF-8]  * @所属包名 [com.xqlee.springmvc.controller]  * @项目名称 [cdws]  * @创建日期 []  * @创建人员 [lxq]  * @最后修改 []  * @修改说明 [暂无更新]  * @修改人员 [lxq]  * @公司组织 [org]  * @版本说明 [v 1.0]  *  * </pre>  */ @Controller(value = "/beanTestController.do") public class BeanTestController {    @RequestMapping(params = "method=Vector")    // @ResponseBody    public Object testVector(HttpServletRequest request,          HttpServletResponse response) {       // 创建容器       Vector<Tobject> vtb = new Vector<Tobject>();       Tobject tb;       for (int i = 0; i <= 5; i++) {          tb = new Tobject("ID-" + i, "名称Name-" + i, "Num-" + i);          vtb.add(tb);       }       request.setAttribute("vtb", vtb);       return "../../vector.jsp";    }      @RequestMapping(params = "method=testJson")    @ResponseBody    public Object testJson(HttpServletRequest request,          HttpServletResponse response) {       // 创建容器       Vector<Tobject> vtb = new Vector<Tobject>();       Tobject tb;       for (int i = 0; i <= 5; i++) {          tb = new Tobject("ID-" + i, "名称Name-" + i, "Num-" + i);          vtb.add(tb);       }       return vtb;    }   }</code></pre>   <p>1.9index.jsp</p> <pre> <code class="language-html"><!DOCTYPE> <html> <body>    <h2>Hello World!</h2>    <a href="beanTestController.do?method=Vector">Vector Test</a> </body> </html></code></pre> <br /> 1.10vector.jsp <pre> <code class="language-html"><%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE> <html> <body>    <table border='1'>       <thead>          <tr>             <td>ID</td>             <td>Name</td>             <td>Num</td>          </tr>       </thead>       <tbody>          <c:forEach items="${vtb}" var="Object">             <tr>                 <td>${Object.id}</td>                 <td>${Object.name}</td>                 <td>${Object.num}</td>             </tr>          </c:forEach>       </tbody>    </table>     </body> </html></code></pre> <br /> 2 SpringMVC4 <p>2.1项目结构图</p> <img alt="2" src="/assist/images/blog/63555b40-5fa1-41e6-9d7c-3d9e088a6223.png" style="height:510px; width:387px" /> <p>2.2pom.xml</p> <pre> <code class="language-xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>seven.org</groupId>    <artifactId>springMVC</artifactId>    <packaging>war</packaging>    <version>0.0.1-SNAPSHOT</version>    <name>springMVC Maven Webapp</name>    <url>http://maven.apache.org</url>    <!-- 属性版本 -->    <properties>       <junit.version>4.12</junit.version>       <spring.version>4.1.7.RELEASE</spring.version>       <org.slf4j.version>1.7.2</org.slf4j.version>       <mysql.driver.version>5.1.32</mysql.driver.version>    <com.fasterxml.jackson.jaxrs.version>2.4.1</com.fasterxml.jackson.jaxrs.version>       <commons-fileupload.version>1.3.1</commons-fileupload.version>      </properties>    <dependencies>         <!-- 测试所需 -->       <dependency>          <groupId>junit</groupId>          <artifactId>junit</artifactId>          <version>${junit.version}</version>          <scope>test</scope>       </dependency>         <!-- spring core -->       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-core</artifactId>          <version>${spring.version}</version>       </dependency>       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-context</artifactId>          <version>${spring.version}</version>       </dependency>       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-web</artifactId>          <version>${spring.version}</version>       </dependency>       <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-webmvc</artifactId>          <version>${spring.version}</version>       </dependency>         <!-- MySQL数据库驱动 导入 start -->       <dependency>          <groupId>mysql</groupId>          <artifactId>mysql-connector-java</artifactId>          <version>${mysql.driver.version}</version>       </dependency>       <!-- MySQL数据库驱动 导入 end -->           <!-- el 标签库 -->       <!-- standard.jar -->       <dependency>          <groupId>taglibs</groupId>          <artifactId>standard</artifactId>          <version>1.1.2</version>       </dependency>       <!-- JSTL -->       <dependency>          <groupId>javax.servlet</groupId>          <artifactId>jstl</artifactId>          <version>1.1.2</version>       </dependency>       <!-- /el 标签库 -->         <!-- 处理json -->       <dependency>          <groupId>com.fasterxml.jackson.jaxrs</groupId>          <artifactId>jackson-jaxrs-xml-provider</artifactId>          <version>${com.fasterxml.jackson.jaxrs.version}</version>       </dependency>         <!-- 文件上传下载 -->       <dependency>          <groupId>commons-fileupload</groupId>          <artifactId>commons-fileupload</artifactId>          <version>${commons-fileupload.version}</version>       </dependency>         <!-- slf4j 和 log4j合用的Maven配置 -->       <dependency>          <groupId>org.slf4j</groupId>          <artifactId>slf4j-log4j12</artifactId>          <version>${org.slf4j.version}</version>       </dependency>      </dependencies>    <build>       <finalName>springMVC</finalName>    </build> </project></code></pre> <br /> 2.3web.xml <pre> <code class="language-xml"><web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"    version="3.0">    <display-name>Archetype Created Web Application</display-name>      <!-- 字符集处理 -->    <filter>       <filter-name>CharacterEncodingFilter</filter-name>       <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>       <init-param>          <param-name>encoding</param-name>          <param-value>utf-8</param-value>       </init-param>    </filter>    <filter-mapping>       <filter-name>CharacterEncodingFilter</filter-name>       <url-pattern>/*</url-pattern>    </filter-mapping>        <!-- spring 核心配置 -->    <context-param>       <param-name>contextConfigLocation</param-name>       <param-value>classpath:/cfg/spring/spring-beans.xml</param-value>    </context-param>    <listener>       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>      <!-- 配置缓存清除监听器,负责处理由 JavaBean Introspector 功能而引起的缓存泄露 -->    <listener>       <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>    </listener>        <!-- springMVC配置 -->    <servlet>       <servlet-name>springMVCSerlet</servlet-name>       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>       <init-param>          <param-name>contextConfigLocation</param-name>          <param-value>classpath:/cfg/spring/spring-servlet.xml</param-value>       </init-param>       <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>       <servlet-name>springMVCSerlet</servlet-name>       <url-pattern>/</url-pattern>    </servlet-mapping>      <!-- 添加下面容器,防止同一个服务器部署多个项目web.root冲突 -->    <context-param>       <param-name>webAppRootKey</param-name>       <param-value>springMVC4</param-value>    </context-param>      <!-- session timeout -->    <session-config>       <!-- 分钟 -->       <session-timeout>60</session-timeout>    </session-config>      <!-- log4j配置 -->    <context-param>       <param-name>log4jConfigLocation</param-name>       <param-value>classpath:/cfg/log/Log4j.properties</param-value>    </context-param>    <context-param>       <param-name>log4jRefreshInterval</param-name>       <param-value>60000</param-value>    </context-param>    <!--添加监听 -->    <listener>       <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>    </listener>    <!-- /log4j配置 -->      <!-- welcome page -->    <welcome-file-list>       <welcome-file>index.html</welcome-file>       <welcome-file>index.jsp</welcome-file>    </welcome-file-list>      <!-- session copy -->    <distributable /> </web-app></code></pre>   <p>2.4 weblogic.xml</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd    http://xmlns.oracle.com/weblogic/weblogic-web-app    http://xmlns.oracle.com/weblogic/weblogic-web-app/1.2/weblogic-web-app.xsd">      <container-descriptor>       <!-- 针对weblogic10以下的版本使用该语句,不能与厦门的prefer-application-packages同时使用 -->       <!-- <prefer-web-inf-classes>true</prefer-web-inf-classes> -->       <!-- 针对weblogic10及以上的版本如果上面语句无法成功使用该语句,不能与厦门的prefer-web-inf-classes同时使用 -->       <prefer-application-packages>          <package-name>org.apache.commons.lang.*</package-name>          <package-name>antlr.*</package-name>          <package-name>org.hibernate.*</package-name>          <package-name>javax.persistence.*</package-name>       </prefer-application-packages>    </container-descriptor> </weblogic-web-app></code></pre>   <p>2.5spring-servlet.xml</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans-4.1.xsd             http://www.springframework.org/schema/mvc             http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd             http://www.springframework.org/schema/context             http://www.springframework.org/schema/context/spring-context-4.1.xsd ">      <!-- 自动扫描controller包下所有 -->    <context:component-scan base-package="com.xqlee.springmvc.controller" />    <!-- 注解驱动 -->    <mvc:annotation-driven />    <mvc:default-servlet-handler />    <!-- 资源管理不拦截 -->    <mvc:resources location="/resources/" mapping="/resources/**" />    <mvc:resources location="/upload/" mapping="/upload/**" />      <!-- 内部资源视图解析器 prefix + logicName + suffix /WEB-INF/jsps/ + index + .jsp -->    <bean id="internalResourceViewResolver"       class="org.springframework.web.servlet.view.InternalResourceViewResolver">       <!-- 前缀 -->       <property name="prefix" value="/WEB-INF/pages/" />       <!-- 后缀 -->       <property name="suffix" value="" />    </bean>      <!-- 处理在controller中使用注解@ResponseBody标签返回JSON数据 Start -->    <!-- 注意[由于我在pom.xml引入的是2.4.1版本]:所以class=org.springframework.http.converter.json.MappingJackson2HttpMessageConverter -->    <!-- [如果pom.xml引入的是1.xx版本]class=org.springframework.http.converter.json.MappingJacksonHttpMessageConverter -->    <bean id="mappingJackson2HttpMessageConverter"    class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">       <property name="supportedMediaTypes">          <list>             <value>text/html;charset=UTF-8</value>             <value>text/json;charset=UTF-8</value>             <value>application/json;charset=UTF-8</value>          </list>       </property>    </bean>    <bean    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">       <property name="messageConverters">          <list>             <ref bean="mappingJackson2HttpMessageConverter" />          </list>       </property>    </bean>    <!-- JSON数据处理 End -->      <!-- 上传图片/文件需要配置 -->    <bean id="multipartResolver"       class="org.springframework.web.multipart.commons.CommonsMultipartResolver">       <property name="maxUploadSize" value="-1" /><!-- -1表示没有限制 -->       <property name="maxInMemorySize" value="4096" />    </bean>   </beans></code></pre>   <p>2.6spring-beans.xml</p> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa"    xsi:schemaLocation="http://www.springframework.org/schema/beans                 http://www.springframework.org/schema/beans/spring-beans-4.1.xsd             http://www.springframework.org/schema/mvc             http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd               http://www.springframework.org/schema/aop             http://www.springframework.org/schema/aop/spring-aop-4.1.xsd             http://www.springframework.org/schema/context             http://www.springframework.org/schema/context/spring-context-4.1.xsd             http://www.springframework.org/schema/tx             http://www.springframework.org/schema/tx/spring-tx-4.1.xsd             http://www.springframework.org/schema/data/jpa             http://www.springframework.org/schema/data/jpa/spring-jpa.xsd ">    <context:annotation-config />    <!-- 启动自动扫描该包下所有的注解(如@controller) 一般扫描service,entity,dao,controller由springMVC扫描 -->    <context:component-scan       base-package="com.xqlee.springmvc.service,com.xqlee.springmvc.entity,com.xqlee.springmvc.dao" /> </beans></code></pre>   <p>2.7 Log4j配置文件</p> <pre> <code>#defind the rooeLogger ,the rootlogger min level is INFO,and two way to output log log4j.rootLogger = INFO,FILE,CONSOLE,DATABASE   #---------------------------------------------------------------------- #defind the FILE as file everyday                                     | #---------------------------------------------------------------------- #log4j.appender.FILE = org.apache.log4j.DailyRollingFileAppender   #the log min level set as INFO #log4j.appender.FILE.Threshold=INFO   #log file encoding set UTF-8 #log4j.appender.FILE.encoding=UTF-8   #log file path #log4j.appender.FILE.File=/home/tomcat/log/springmvc4/springmvc4   #log file name append #log4j.appender.FILE.DatePattern='_'yyyy-MM-dd'.log'   #Immediate write the log is true #log4j.appender.FILE.ImmediateFlush=true   #the layout of the log #log4j.appender.FILE.layout=org.apache.log4j.PatternLayout   #the detail layout of log  in the log file #log4j.appender.FILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} springmvc4 %-5p [%c:%L] | %m%n   #------------------------------------------------------------------------- #this use the 'org.apache.log4j.ConsoleAppender' to output in the Console| #------------------------------------------------------------------------- log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender   #output min level is INFO log4j.appender.Threshold=INFO   #the output target is Console log4j.appender.CONSOLE.Target=System.out   #the layout of the log log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} springmvc4 %-5p | %m%n   #---------------------------------------------------------------------------- #insert the log into database                                               | #---------------------------------------------------------------------------- #log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender #The jdbc url #log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/springmvc4 #The jdbc driver #log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver #DB user #log4j.appender.DATABASE.user=root #DB password #log4j.appender.DATABASE.password=root #sql #log4j.appender.DATABASE.sql=INSERT INTO zhl_log (operationTime,logLevel,logClass,logDetail)  VALUES ("%d{yyyy-MM-dd HH:mm:ss}", "%-5p","%F:%L", "%m") #layout #log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout #layout detail #log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</code></pre>   <p>2.8测试vo</p> <pre> <code class="language-java">package com.xqlee.springmvc.vo;   /**  *  *  * <pre>  * @功能说明 [测试bean]  * @其他说明 [暂无]  * @文件编码 [UTF-8]  * @所属包名 [com.xqlee.springmvc.vo]  * @项目名称 [cdws]  * @创建日期 []  * @创建人员 [lxq]  * @最后修改 []  * @修改说明 [暂无更新]  * @修改人员 [lxq]  * @公司组织 [org]  * @版本说明 [v 1.0]  *  * </pre>  */ public class User {      private String id;    private String name;    private String num;      public User(String id, String name, String num) {       this.id = id;       this.name = name;       this.num = num;    }      public String getId() {       return id;    }      public void setId(String id) {       this.id = id;    }      public String getName() {       return name;    }      public void setName(String name) {       this.name = name;    }      public String getNum() {       return num;    }      public void setNum(String num) {       this.num = num;    }   }</code></pre>   <p>2.9测试controller</p> <pre> <code class="language-java">package com.xqlee.springmvc.controller;   import java.util.Vector;   import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;   import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;   import com.xqlee.springmvc.vo.User;   /**  *  *  * <pre>  * &#64;功能说明 [测试类]  * &#64;其他说明 [暂无]  * &#64;文件编码 [UTF-8]  * &#64;所属包名 [com.xqlee.springmvc.controller]  * &#64;项目名称 [cdws]  * &#64;创建日期 []  * &#64;创建人员 [lxq]  * &#64;最后修改 []  * &#64;修改说明 [暂无更新]  * &#64;修改人员 [lxq]  * &#64;公司组织 [org]  * &#64;版本说明 [v 1.0]  *  * </pre>  */ @Controller(value = "/beanTestController.do") public class TestController {    /** 日志 **/    private static final Log log = LogFactory.getLog(TestController.class);      @RequestMapping(params = "method=Vector")    // @ResponseBody    public Object testVector(HttpServletRequest request, HttpServletResponse response) {       // 创建容器       Vector<User> vtb = new Vector<User>();       User tb;       for (int i = 0; i <= 5; i++) {          tb = new User("ID-" + i, "小Name-" + i, "李Num-" + i);          vtb.add(tb);       }       request.setAttribute("vtb", vtb);       log.info("即将跳转.....");       return "../../vector.jsp";    } }</code></pre>   <p>2.10 index.jsp</p> <pre> <code class="language-html"><!DOCTYPE> <html> <body>    <h2>Hello World!</h2>    <a href="beanTestController.do?method=Vector">Vector Test</a> </body> </html></code></pre>   <p>2.11 vector.jsp</p> <pre> <code class="language-html"><%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE> <html> <body>    <table border='1'>       <thead>          <tr>             <td>ID</td>             <td>Name</td>             <td>Num</td>          </tr>       </thead>       <tbody>          <c:forEach items="${vtb}" var="Object">             <tr>                 <td>${Object.id}</td>                 <td>${Object.name}</td>                 <td>${Object.num}</td>             </tr>          </c:forEach>       </tbody>    </table>     </body> </html></code></pre>   <p>2.12运行结果</p> <img alt="3" src="/assist/images/blog/d439127f-c160-4faa-a47b-1f3118f87ba5.png" style="height:213px; width:422px" /><br /> <img alt="4" src="/assist/images/blog/46005b58-d05f-4bab-b517-11ed209014c9.png" style="height:486px; width:611px" /><br />  
  • Spring框架与线程安全

    Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但其实,Spring并没有保证这些对象的线程安全,需要由开发者自己编写解决线程安全问题的代码。<p>Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但其实,Spring并没有保证这些对象的线程安全,需要由开发者自己编写解决线程安全问题的代码。</p> <p>Spring对每个bean提供了一个scope属性来表示该bean的作用域。它是bean的生命周期。例如,一个scope为singleton的bean,在第一次被注入时,会创建为一个单例对象,该对象会一直被复用到应用结束。</p> <ul> <li> <p>singleton:默认的scope,每个scope为singleton的bean都会被定义为一个单例对象,该对象的生命周期是与Spring IOC容器一致的(但在第一次被注入时才会创建)。</p> </li> <li> <p>prototype:bean被定义为在每次注入时都会创建一个新的对象。</p> </li> <li> <p>request:bean被定义为在每个HTTP请求中创建一个单例对象,也就是说在单个请求中都会复用这一个单例对象。</p> </li> <li> <p>session:bean被定义为在一个session的生命周期内创建一个单例对象。</p> </li> <li> <p>application:bean被定义为在ServletContext的生命周期中复用一个单例对象。</p> </li> <li> <p>websocket:bean被定义为在websocket的生命周期中复用一个单例对象。</p> </li> </ul> <p>我们交由Spring管理的大多数对象其实都是一些无状态的对象,这种不会因为多线程而导致状态被破坏的对象很适合Spring的默认scope,每个单例的无状态对象都是线程安全的(也可以说只要是无状态的对象,不管单例多例都是线程安全的,不过单例毕竟节省了不断创建对象与GC的开销)。</p> <p>无状态的对象即是自身没有状态的对象,自然也就不会因为多个线程的交替调度而破坏自身状态导致线程安全问题。无状态对象包括我们经常使用的DO、DTO、VO这些只作为数据的实体模型的贫血对象,还有Service、DAO和Controller,这些对象并没有自己的状态,它们只是用来执行某些操作的。例如,每个DAO提供的函数都只是对数据库的CRUD,而且每个数据库Connection都作为函数的局部变量(局部变量是在用户栈中的,而且用户栈本身就是线程私有的内存区域,所以不存在线程安全问题),用完即关(或交还给连接池)。</p> <p>有人可能会认为,我使用request作用域不就可以避免每个请求之间的安全问题了吗?这是完全错误的,因为Controller默认是单例的,一个HTTP请求是会被多个线程执行的,这就又回到了线程的安全问题。当然,你也可以把Controller的scope改成prototype,实际上Struts2就是这么做的,但有一点要注意,Spring MVC对请求的拦截粒度是基于每个方法的,而Struts2是基于每个类的,所以把Controller设为多例将会频繁的创建与回收对象,严重影响到了性能。</p> <p>通过阅读上文其实已经说的很清楚了,Spring根本就没有对bean的多线程安全问题做出任何保证与措施。对于每个bean的线程安全问题,根本原因是每个bean自身的设计。不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。<br /> 下面将通过解析ThreadLocal的源码来了解它的实现与作用,ThreadLocal是一个很好用的工具类,它在某些情况下解决了线程安全问题(在变量不需要被多个线程共享时)。</p> <h2>ThreadLocal</h2> <p>ThreadLocal是一个为线程提供线程局部变量的工具类。它的思想也十分简单,就是为线程提供一个线程私有的变量副本,这样多个线程都可以随意更改自己线程局部的变量,不会影响到其他线程。不过需要注意的是,ThreadLocal提供的只是一个浅拷贝,如果变量是一个引用类型,那么就要考虑它内部的状态是否会被改变,想要解决这个问题可以通过重写ThreadLocal的initialValue()函数来自己实现深拷贝,建议在使用ThreadLocal时一开始就重写该函数。</p> <p>ThreadLocal与像synchronized这样的锁机制是不同的。首先,它们的应用场景与实现思路就不一样,锁更强调的是如何同步多个线程去正确地共享一个变量,ThreadLocal则是为了解决同一个变量如何不被多个线程共享。从性能开销的角度上来讲,如果锁机制是用时间换空间的话,那么ThreadLocal就是用空间换时间。</p> <p>ThreadLocal中含有一个叫做ThreadLocalMap的内部类,该类为一个采用线性探测法实现的HashMap。它的key为ThreadLocal对象而且还使用了WeakReference,ThreadLocalMap正是用来存储变量副本的。</p> <pre> <code class="language-java">/** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } .... }</code></pre> <p>ThreadLocal中只含有三个成员变量,这三个变量都是与ThreadLocalMap的hash策略相关的。<br />  </p> <pre> <code class="language-java">/** * ThreadLocals rely on per-thread linear-probe hash maps attached * to each thread (Thread.threadLocals and * inheritableThreadLocals). The ThreadLocal objects act as keys, * searched via threadLocalHashCode. This is a custom hash code * (useful only within ThreadLocalMaps) that eliminates collisions * in the common case where consecutively constructed ThreadLocals * are used by the same threads, while remaining well-behaved in * less common cases. */ private final int threadLocalHashCode = nextHashCode(); /** * The next hash code to be given out. Updated atomically. Starts at * zero. */ private static AtomicInteger nextHashCode = new AtomicInteger(); /** * The difference between successively generated hash codes - turns * implicit sequential thread-local IDs into near-optimally spread * multiplicative hash values for power-of-two-sized tables. */ private static final int HASH_INCREMENT = 0x61c88647; /** * Returns the next hash code. */ private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }</code></pre> 唯一的实例变量threadLocalHashCode是用来进行寻址的hashcode,它由函数nextHashCode()生成,该函数简单地通过一个增量HASH_INCREMENT来生成hashcode。至于为什么这个增量为0x61c88647,主要是因为ThreadLocalMap的初始大小为16,每次扩容都会为原来的2倍,这样它的容量永远为2的n次方,该增量选为0x61c88647也是为了尽可能均匀地分布,减少碰撞冲突。 <pre> <code class="language-java">/** * The initial capacity -- MUST be a power of two. */ private static final int INITIAL_CAPACITY = 16; /** * Construct a new map initially containing (firstKey, firstValue). * ThreadLocalMaps are constructed lazily, so we only create * one when we have at least one entry to put in it. */ ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }</code></pre> <p>要获得当前线程私有的变量副本需要调用get()函数。首先,它会调用getMap()函数去获得当前线程的ThreadLocalMap,这个函数需要接收当前线程的实例作为参数。如果得到的ThreadLocalMap为null,那么就去调用setInitialValue()函数来进行初始化,如果不为null,就通过map来获得变量副本并返回。</p> <p>setInitialValue()函数会去先调用initialValue()函数来生成初始值,该函数默认返回null,我们可以通过重写这个函数来返回我们想要在ThreadLocal中维护的变量。之后,去调用getMap()函数获得ThreadLocalMap,如果该map已经存在,那么就用新获得value去覆盖旧值,否则就调用createMap()函数来创建新的map。<br />  </p> <pre> <code class="language-java">/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } /** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * @return the initial value */ private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } protected T initialValue() { return null; }</code></pre> ThreadLocal的set()与remove()函数要比get()的实现还要简单,都只是通过getMap()来获得ThreadLocalMap然后对其进行操作。 <pre> <code class="language-java">/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } /** * Removes the current thread's value for this thread-local * variable. If this thread-local variable is subsequently * {@linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {@link #initialValue} method, * unless its value is {@linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * {@code initialValue} method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }</code></pre> getMap()函数与createMap()函数的实现也十分简单,但是通过观察这两个函数可以发现一个秘密:ThreadLocalMap是存放在Thread中的。 <pre> <code class="language-java">/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; } /** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } // Thread中的源码 /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;</code></pre> <p>仔细想想其实就能够理解这种设计的思想。有一种普遍的方法是通过一个全局的线程安全的Map来存储各个线程的变量副本,但是这种做法已经完全违背了ThreadLocal的本意,设计ThreadLocal的初衷就是为了避免多个线程去并发访问同一个对象,尽管它是线程安全的。而在每个Thread中存放与它关联的ThreadLocalMap是完全符合ThreadLocal的思想的,当想要对线程局部变量进行操作时,只需要把Thread作为key来获得Thread中的ThreadLocalMap即可。这种设计相比采用一个全局Map的方法会多占用很多内存空间,但也因此不需要额外的采取锁等线程同步方法而节省了时间上的消耗。</p> <h2>ThreadLocal中的内存泄漏</h2> <p>我们要考虑一种会发生内存泄漏的情况,如果ThreadLocal被设置为null后,而且没有任何强引用指向它,根据垃圾回收的可达性分析算法,ThreadLocal将会被回收。这样一来,ThreadLocalMap中就会含有key为null的Entry,而且ThreadLocalMap是在Thread中的,只要线程迟迟不结束,这些无法访问到的value会形成内存泄漏。为了解决这个问题,ThreadLocalMap中的getEntry()、set()和remove()函数都会清理key为null的Entry,以下面的getEntry()函数的源码为例。<br />  </p> <pre> <code class="language-java">/** * Get the entry associated with key. This method * itself handles only the fast path: a direct hit of existing * key. It otherwise relays to getEntryAfterMiss. This is * designed to maximize performance for direct hits, in part * by making this method readily inlinable. * * @param key the thread local object * @return the entry associated with key, or null if no such */ private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } /** * Version of getEntry method for use when key is not found in * its direct hash slot. * * @param key the thread local object * @param i the table index for key's hash code * @param e the entry at table[i] * @return the entry associated with key, or null if no such */ private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; // 清理key为null的Entry while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; }</code></pre> <p>在上文中我们发现了ThreadLocalMap的key是一个弱引用,那么为什么使用弱引用呢?使用强引用key与弱引用key的差别如下:</p> <ul> <li> <p><strong>强引用key</strong>:ThreadLocal被设置为null,由于ThreadLocalMap持有ThreadLocal的强引用,如果不手动删除,那么ThreadLocal将不会回收,产生内存泄漏。</p> </li> <li> <p><strong>弱引用key</strong>:ThreadLocal被设置为null,由于ThreadLocalMap持有ThreadLocal的弱引用,即便不手动删除,ThreadLocal仍会被回收,ThreadLocalMap在之后调用set()、getEntry()和remove()函数时会清除所有key为null的Entry。</p> </li> </ul> <p>但要注意的是,ThreadLocalMap仅仅含有这些被动措施来补救内存泄漏问题。如果你在之后没有调用ThreadLocalMap的set()、getEntry()和remove()函数的话,那么仍然会存在内存泄漏问题。<br /> 在使用线程池的情况下,如果不及时进行清理,内存泄漏问题事小,甚至还会产生程序逻辑上的问题。所以,<strong>为了安全地使用ThreadLocal,必须要像每次使用完锁就解锁一样,在每次使用完ThreadLocal后都要调用remove()来清理无用的Entry</strong>。</p>