Java:Spring Framework中自带类的加载

环境

  • Spring Boot版本: 2.1.4.RELEASE
  • Spring Framework版本: 5.1.6.RELEASE

java

1. 加载类和方法说明

所有Spring框架自带的类,均通过下面的方法加载:

所在类:

AbstractAutowireCapableBeanFactory.java:550

所属方法:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean

2. 使用的Maven的pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>xyz.suancaiyu</groupId>
   <artifactId>SpringBootVueJSTest</artifactId>
   <version>1.0-SNAPSHOT</version>
   <description>Spring Boot + Thymeleaf + VueJS (Element-UI)</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.4.RELEASE</version>
   </parent>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
   </dependencies>
</project>

3. 使用的IDEA调试参数截图:

idea调试Spring Boot截图
image-2712

Java:Spring Bean注入点

1. 实现org.springframework.beans.factory.InitializingBean接口,可以注册bean.

java

public class AnotherExampleBean implements InitializingBean {

    public void afterPropertiesSet() {
        // do some initialization work
    }
}

1.1 实现org.springframework.beans.factory.DisposableBean接口,可以在bean销毁前执行某些操作.

public class AnotherExampleBean implements DisposableBean {

    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}

2. 实现ApplicationContextAware 或者 BeanNameAware 接口.

3. 其他Ware接口

Spring 其他Ware接口

Java:使用Spring Mail发送邮件

发送邮件

本项目源码在:https://coding.net/u/pruidong/p/SpringEmailDemo/git

之前简单使用过Java Email发送邮件,但最近接触了Spring Mail组件之后,发现在之前的基础上更加方便了.本文的内容参照了:Spring Mail官方文档,以及Thymeleaf官方示例.但对部分内容进行了修改和优化,也使得发送邮件变得更加简单.

有两点需要说明的是:

  1. 本文不会贴完所有的资源,可以前往[项目地址]获取所有源码;
  2. 项目基于Maven构建,并且不需要Spring Web MVC(也就是不需要在Tomcat中运行),配置相关邮箱信息之后,直接在控制台运行即可
Spring Mail发送邮件项目结构图
Spring Mail发送邮件项目结构图

部分源码

直接使用下面的源码无法构建出完整项目,因为有部分图片、模板文件(HTML,txt)未贴出,贴出下面的代码,仅作为参考依据.完整源码可以访问项目地址

Maven依赖文件(pom.xml):

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xyz.suancaiyu</groupId>
    <artifactId>SpringMail19Demo</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.11.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.11.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.11.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring4</artifactId>
            <version>3.0.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.9.0</version>
        </dependency>


        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>


    </dependencies>


</project>

java标志

配置邮箱地址、邮箱服务器信息(base.properties):

xyz.suancaiyu.smtpServer=SMTP服务器地址(smtp.qq.com)
xyz.suancaiyu.smtpServerPort=SMTP服务器端口
xyz.suancaiyu.smtpUserName=邮箱登录名
xyz.suancaiyu.smtpUserPassword=邮箱登录密码(QQ邮箱要使用授权码)
xyz.suancaiyu.smtpFromEmail=发件人邮箱地址
xyz.suancaiyu.smtpToEmail=收件人邮箱地址

Spring的配置文件(AppInitial.java):

package xyz.suancaiyu.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.templateresolver.StringTemplateResolver;
import xyz.suancaiyu.Constat;

import java.util.Collections;
import java.util.Properties;

/**
 * Spring 配置文件.
 *
 * Created by puruidong on 2017/9/15.
 */
@Configuration
@ComponentScan(basePackages = "xyz.suancaiyu.*")
public class AppInitial {


    @Bean
    public SimpleMailMessage templateMessage() {
        SimpleMailMessage msg = new SimpleMailMessage();
        msg.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
        msg.setTo(Constat.getValue(Constat.SMTPTOEMAIL));
        return msg;
    }

    @Bean
    public JavaMailSenderImpl mailSender() {
        JavaMailSenderImpl jmsl = new JavaMailSenderImpl();
        jmsl.setHost(Constat.getValue(Constat.SMTPSERVER));
        jmsl.setPort(Integer.valueOf(Constat.getValue(Constat.SMTPSERVERPORT)));
        jmsl.setUsername(Constat.getValue(Constat.SMTPUSERNAME));
        jmsl.setPassword(Constat.getValue(Constat.SMTPPASSWORD));
        Properties properties = new Properties();
        properties.setProperty("mail.smtp.auth", "true");
        properties.setProperty("mail.smtp.ssl.enable", "true");
        properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        jmsl.setJavaMailProperties(properties);
        return jmsl;
    }

    /********* Thymeleaf Email Template **************/

    @Bean
    public ResourceBundleMessageSource emailMessageSource() {
        final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("mail/MailMessages");
        return messageSource;
    }


    @Bean
    public TemplateEngine emailTemplateEngine() {
        final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        // Resolver for TEXT emails
        templateEngine.addTemplateResolver(textTemplateResolver());
        // Resolver for HTML emails (except the editable one)
        templateEngine.addTemplateResolver(htmlTemplateResolver());
        // Resolver for HTML editable emails (which will be treated as a String)
        templateEngine.addTemplateResolver(stringTemplateResolver());
        // Message source, internationalization specific to emails
        templateEngine.setTemplateEngineMessageSource(emailMessageSource());
        return templateEngine;
    }

    private ITemplateResolver textTemplateResolver() {
        final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setOrder(Integer.valueOf(1));
        templateResolver.setResolvablePatterns(Collections.singleton("text/*"));
        templateResolver.setPrefix("/mail/");
        templateResolver.setSuffix(".txt");
        templateResolver.setTemplateMode(TemplateMode.TEXT);
        templateResolver.setCharacterEncoding(Constat.EMAIL_TEMPLATE_ENCODING);
        templateResolver.setCacheable(false);
        return templateResolver;
    }

    private ITemplateResolver htmlTemplateResolver() {
        final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
        templateResolver.setOrder(Integer.valueOf(2));
        templateResolver.setResolvablePatterns(Collections.singleton("html/*"));
        templateResolver.setPrefix("/mail/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCharacterEncoding(Constat.EMAIL_TEMPLATE_ENCODING);
        templateResolver.setCacheable(false);
        return templateResolver;
    }

    private ITemplateResolver stringTemplateResolver() {
        final StringTemplateResolver templateResolver = new StringTemplateResolver();
        templateResolver.setOrder(Integer.valueOf(3));
        // No resolvable pattern, will simply process as a String template everything not previously matched
        templateResolver.setTemplateMode("HTML5");
        templateResolver.setCacheable(false);
        return templateResolver;
    }

    /********* Thymeleaf Email Template END **************/


}

发送纯文本邮件(未使用模板,SendTextEmail.java):

package xyz.suancaiyu.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Component;

import java.time.LocalDate;

/**
 * 发送纯文本邮件.
 * <p>
 * <p>
 * Created by puruidong on 2017/9/15.
 */
@Component
public class SendTextEmail {

    @Autowired
    private SimpleMailMessage templateMessage;

    @Autowired
    private MailSender mailSender;

    public void sendEmail() {
        System.out.println("发送纯文本邮件:");
        templateMessage.setSubject("订单信息-" + LocalDate.now().toString());
        templateMessage.setText("你好,email测试. ");
        mailSender.send(templateMessage);
        System.out.println("发送成功..");
    }

}

发送带附件的邮件(SendFileEmail.java):

package xyz.suancaiyu.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import xyz.suancaiyu.Constat;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import static xyz.suancaiyu.Constat.PNG_MIME;

/**
 * 发送邮件-带附件.
 * <p>
 * Created by puruidong on 2017/9/15.
 */
@Component
public class SendFileEmail {


    @Autowired
    private JavaMailSenderImpl mailSender;

    public void sendEmail() {
        System.out.println("发送邮件,携带附件:");
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setTo(Constat.getValue(Constat.SMTPTOEMAIL));
            helper.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
            helper.setText("订单消息-详情请查看附件");
            helper.setSubject("订单消息");
            helper.addAttachment("detail.jpg", new ClassPathResource(Constat.THYMELEAF_LOGO_IMAGE), PNG_MIME);
            mailSender.send(message);
            System.out.println("发送成功!");
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    public void sendHTMLEmail() {
        System.out.println("发送HTML邮件:");
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "GBK");
            helper.setTo(Constat.getValue(Constat.SMTPTOEMAIL));
            helper.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
            helper.setText("<mail.html><head><META http-equiv=Content-Type content='text/mail.html; charset=GBK'> <meta charset='utf-8'/><head><body><img src='cid:identifier1234'><b>测试一个文本.</b><p style='color:red'>重要提示.</p></body></mail.html>", true);
            helper.setSubject("订单消息");
            helper.addInline("identifier1234", new ClassPathResource(Constat.THYMELEAF_LOGO_IMAGE), PNG_MIME);
            mailSender.send(message);
            System.out.println("发送成功!");
        } catch (MessagingException e) {
            e.printStackTrace();
        }


    }


}

使用Thymeleaf发送模板邮件(参照了Thymeleaf官方示例,有部分改动):

package xyz.suancaiyu.service.thymeleaf;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import xyz.suancaiyu.Constat;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Arrays;
import java.util.Date;


/**
 * 使用Thymeleaf发送模板邮件.
 * 
 * Created by puruidong on 2017/9/15.
 */
@Component
public class EmailService {

    @Autowired
    private JavaMailSenderImpl mailSender;

    @Autowired
    private TemplateEngine emailTemplateEngine;

    private static final String EMAIL_TEXT_TEMPLATE_NAME = "text/email-text";
    private static final String EMAIL_SIMPLE_TEMPLATE_NAME = "html/email-simple";
    private static final String EMAIL_WITHATTACHMENT_TEMPLATE_NAME = "html/email-withattachment";
    private static final String EMAIL_INLINEIMAGE_TEMPLATE_NAME = "html/email-inlineimage";
    private static final String EMAIL_EDITABLE_TEMPLATE_CLASSPATH_RES = "html/email-editable";

    public void sendTextMail() {
        // Prepare the evaluation context
        final Context ctx = new Context();
        ctx.setVariable("name", "test123");
        ctx.setVariable("subscriptionDate", new Date());
        ctx.setVariable("hobbies", Arrays.asList("Cinema", "Sports", "Music"));

        // Prepare message using a Spring helper
        final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
        final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
        try {
            message.setSubject("Example plain TEXT email");
            message.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
            message.setTo(Constat.getValue(Constat.SMTPTOEMAIL));

            // Create the plain TEXT body using Thymeleaf
            final String textContent = emailTemplateEngine.process(EMAIL_TEXT_TEMPLATE_NAME, ctx);
            message.setText(textContent);

            // Send email
            mailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

    /*
     * Send HTML mail (simple)
     */
    public void sendSimpleMail() {

        // Prepare the evaluation context
        final Context ctx = new Context();
        ctx.setVariable("name", "13343sdsxvbn");
        ctx.setVariable("subscriptionDate", new Date());
        ctx.setVariable("hobbies", Arrays.asList("Cinema", "Sports", "Music"));

        // Prepare message using a Spring helper
        final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
        final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
        try {
            message.setSubject("Example HTML email (simple)");
            message.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
            message.setTo(Constat.getValue(Constat.SMTPTOEMAIL));

            // Create the HTML body using Thymeleaf
            final String htmlContent = emailTemplateEngine.process(EMAIL_SIMPLE_TEMPLATE_NAME, ctx);
            message.setText(htmlContent, true /* isHtml */);

            // Send email
            this.mailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }

    }


    public void sendMailWithInline() {
        final Context ctx = new Context();
        ctx.setVariable("name", "testlocal");
        ctx.setVariable("subscriptionDate", new Date());
        ctx.setVariable("hobbies", Arrays.asList("Cinema", "Sports", "Music"));
        ctx.setVariable("imageResourceName", "identifier1234"); // so that we can reference it from HTML

        final MimeMessage mimeMessage = mailSender.createMimeMessage();
        try {
            final MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
            helper.setSubject("Thymeleaf模板邮件");
            helper.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
            helper.setTo(Constat.getValue(Constat.SMTPTOEMAIL));
            final String htmlContent = emailTemplateEngine.process(EMAIL_INLINEIMAGE_TEMPLATE_NAME, ctx);
            helper.setText(htmlContent, true);

            helper.addInline("identifier1234", new ClassPathResource(Constat.THYMELEAF_LOGO_IMAGE), Constat.PNG_MIME);
            mailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }


    /*
     * Send HTML mail with inline image
     */
    public void sendEditableMail() {
        try {
            // Prepare message using a Spring helper
            final MimeMessage mimeMessage = mailSender.createMimeMessage();
            final MimeMessageHelper message
                    = new MimeMessageHelper(mimeMessage, true /* multipart */, "UTF-8");
            message.setSubject("Example editable HTML email");
            message.setFrom(Constat.getValue(Constat.SMTPFROMEMAIL));
            message.setTo(Constat.getValue(Constat.SMTPTOEMAIL));

            // Prepare the evaluation context
            final Context ctx = new Context();
            ctx.setVariable("name", "fdsafdsadsaork11233");
            ctx.setVariable("subscriptionDate", new Date());
            ctx.setVariable("hobbies", Arrays.asList("Cinema", "Sports", "Music"));

            // Create the HTML body using Thymeleaf
            final String output = emailTemplateEngine.process(EMAIL_EDITABLE_TEMPLATE_CLASSPATH_RES, ctx);
            message.setText(output, true /* isHtml */);

            // Add the inline images, referenced from the HTML code as "cid:image-name"
            message.addInline("background", new ClassPathResource(Constat.BACKGROUND_IMAGE), Constat.PNG_MIME);
            message.addInline("logo-background", new ClassPathResource(Constat.LOGO_BACKGROUND_IMAGE), Constat.PNG_MIME);
            message.addInline("thymeleaf-banner", new ClassPathResource(Constat.THYMELEAF_BANNER_IMAGE), Constat.PNG_MIME);
            message.addInline("thymeleaf-logo", new ClassPathResource(Constat.THYMELEAF_LOGO_IMAGE), Constat.PNG_MIME);

            // Send mail
            mailSender.send(mimeMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

运行测试类(Main.java):

package xyz.suancaiyu.main;


import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import xyz.suancaiyu.config.AppInitial;
import xyz.suancaiyu.service.SendFileEmail;
import xyz.suancaiyu.service.SendTextEmail;
import xyz.suancaiyu.service.thymeleaf.EmailService;

/**
 * 使用Spring mail发送邮件.
 * <p>
 * <p>
 * <p>
 * 可能出现的问题:
 * <p>
 * <p>
 * 1.增加验证,否则会报:553 authentication is required 的错误信息
 * Properties prop = new Properties();
 * prop.setProperty("mail.smtp.auth", "true");
 * JavaMailSenderImpl.setJavaMailProperties(prop);
 * <p>
 * 2.当邮件内容是HTML语言时的中文问题:
 * 初始化MimeMessageHelper辅助类时,设置"GBK" encoding!如:
 * MimeMessageHelper messageHelp = new MimeMessageHelper(message,true,"GBK");
 * 同时在设置:<META http-equiv=Content-Type content='text/mail.html; charset=GBK'>
 * 如果都设置为"UTF-8",在某些邮件客户端标题不能正常显示!
 * <p>
 * 3.邮件附件的中文问题!
 * spring的文档里面说MimeMessageHelper设置了encoding,同时对title,text,attach产生作用,但还是会出问题:
 * 解决方法:MimeUtility.encodeWord(file.getName());就OK了!
 * <p>
 * Created by puruidong on 2017/9/15.
 */
public class Main {

    private static final ApplicationContext ctx = new AnnotationConfigApplicationContext(AppInitial.class);

    /**
     * 发送文本邮件.
     */
    private static void sendTextEmail() {
        SendTextEmail send = ctx.getBean(SendTextEmail.class);
        send.sendEmail();
    }

    /**
     * 发送文件邮件.
     */
    private static void sendFileEmail() {
        SendFileEmail send = ctx.getBean(SendFileEmail.class);
        send.sendEmail();
        send.sendHTMLEmail();
    }

    /**
     * 使用Thymeleaf模板发送模板邮件.
     * <p>
     * 参考:https://github.com/thymeleaf/thymeleafexamples-springmail
     */
    private static void sendThymeleafEmail() {
        EmailService emailService = ctx.getBean(EmailService.class);
        emailService.sendMailWithInline();
        emailService.sendTextMail();
        emailService.sendSimpleMail();
        emailService.sendEditableMail();
    }

    public static void main(String[] args) {
        System.out.println("先配置base.properties");
        System.exit(1);
        sendThymeleafEmail();
    }
}

到此.

Java:Spring MVC上传文件实战

一直很麻烦

说实话,Java的上传文件,还是稍微有点麻烦,要自己集成很多东西.在这一点上,我发现我更喜欢Flask的文件上传,寥寥几行就可以搞定文件上传.

看个Flask官方的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files['file']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('uploaded_file',
                                    filename=filename))
    return '''
    &lt;!doctype html&gt;
    &lt;title&gt;Upload new File&lt;/title&gt;
    &lt;h1&gt;Upload new File&lt;/h1&gt;
    &lt;form action="" method=post enctype=multipart/form-data&gt;
      &lt;p&gt;&lt;input type=file name=file&gt;
         &lt;input type=submit value=Upload&gt;
    &lt;/form&gt;
    '''

搞定,关于Flask还有很多美好的传说..有意,请自行探索.

从一而终,看Java文件上传

在这里,我使用了Ajax上传文件.(不刷新页面,可以让你有更大的想象空间)

特诊如下:

  1. 使用了jquery.js,jquery.form.js,layer.js;
  2. 使用Ajax进行文件上传;
  3. 推荐使用iframe的方式进行调用,上传成功之后,ID会放进一个隐藏域.

大概特征如上,下面……兴奋的看源码吧.

java
image-2464

源码有点多…

第一个文件:前台upload.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
&lt;%@ page contentType="text/html;charset=UTF-8" %&gt;
&lt;%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;文件上传&lt;/title&gt;
    &lt;meta name="decorator" content="default"/&gt;
    &lt;script type="text/javascript" src="/jquery/jquery.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="/jquery/jquery.form.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="/layer/layer.js"&gt;&lt;/script&gt;
    &lt;script type="text/javascript"&gt;
    &lt;c:if test="${empty list }"&gt;
        $(document).ready(function() {
            $(".deletefile").live("click",function(){ // 动态绑定删除按钮.
                var delid = $(this).data("id");
                var buttondel = $(this);
                if(delid){
                    //询问框
                top.layer.confirm('确认要删除吗?', {
                      btn: ['确认','取消'] //按钮
                    }, function(index){
                        top.layer.close(index);
                        $.ajax({
                            url:"/deleteFile",
                            data:{
                                "fileId":delid
                            },
                            type:"POST",
                            dataType:"json",
                            success:function(data){
                                if(data.status &amp;&amp; data.status=='0'){
                                    //将已删除的id从隐藏域中删除
                                    var idStr = $("#resultIdInfo").val();
                                    idStr = idStr.substring(0,idStr.length-1);
                                    var array = idStr.split(",");
                                    var indexarray = array.indexOf(delid);//找到相应ID的项
                                    if (indexarray &gt; -1) {
                                        array.splice(indexarray, 1);//在数组中删除相应项
                                    }
                                    $("#resultIdInfo").val("");
                                    if(array.length&gt;0){//如果没有值了,不要添加.                                       
                                        $("#resultIdInfo").val(array.join(",")+",");
                                    }
                                    buttondel.parent().parent().remove();//删除当前行.
                                }
                            }
                        });
                       
                    });
                }
               
            })
           
           
            $("#upload").click(function(){ // 上传操作
                 var fileinput=$("#file");
                  if($.trim(fileinput.val())==''){ // 判断是否已经选择了文件
                         top.layer.msg('请先选择文件!');
                         return false;
                   }
                      $("#uploadForm").ajaxSubmit({ // 使用ajax上传
                          type: "post",
                          url: $("#uploadForm").attr("action"),
                          success: function (data) {
                                if(data.status &amp;&amp; data.status=='0'){//成功.
                                    var objinfo = data.result; // 会返回id和displayName.
                                    if(!checkIdRepeat(objinfo.id)){ // 判断id还不存在
                                        var resultValue = $("#resultIdInfo");
                                        resultValue.val(resultValue.val()+objinfo.id+","); // 添加到隐藏域
                                        $("#fileInfoTable").append(generatorTrHTML(objinfo.id,objinfo.displayName)); // 添加到表格
                                    }
                                    // 清空文件选择
                                    fileinput.after(fileinput.clone().val(""));    
                                    fileinput.remove();    
                                }else{
                                    top.layer.msg(data.msg);
                                }                              
                          },
                          error: function (msg) {
                              top.layer.msg("文件上传失败!");    
                          }
                      });
                      return false;
                 
            })
        });
       
        //拼接html.
        function generatorTrHTML(id,name){
            return "&lt;tr id='"+id+"'&gt;&lt;td&gt;"+name+"&lt;/td&gt;&lt;td&gt;&lt;input type='button' data-id='"
                        +id+"' class='btn btn-danger deletefile' value='删除'/&gt;&amp;nbsp;&amp;nbsp;&lt;input type='button' onclick='window.open("/viewfile/"+id+"")'  class='btn btn-primary' value='下载'/&gt;&lt;/td&gt;&lt;/tr&gt;";
        }
       
        // 检查是否已经存在ID了.
        function checkIdRepeat(fileid){
            var resultValue = $("#resultIdInfo").val();
            if(resultValue &amp;&amp; resultValue.indexOf(fileid)&gt;0){
                return true;
            }
            return false;
        }
        &lt;/c:if&gt;
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;form:form id="uploadForm" enctype="multipart/form-data" modelAttribute="document" action="/saveFile" method="post" class="breadcrumb form-search "&gt;
        &lt;c:if test="${empty list }"&gt;&lt;!-- 如果为空才可以进行文件选择 --&gt;
            &lt;input id="fileUploadType" name="fileUploadType" type="hidden" value="${fileUploadType}"/&gt;
            &lt;input type="file" id="file" name="file" /&gt;
            &lt;input type="button" id="upload" class="default"  &lt;c:if test="${empty fileUploadType}"&gt;disabled="disabled"&lt;/c:if&gt; value="上传"/&gt;&lt;c:if test="${empty fileUploadType}"&gt;&lt;span&gt;文件上传类型为空,暂时不能上传!&lt;/span&gt;&lt;/c:if&gt;
            &lt;input type="hidden" id="resultIdInfo"  /&gt;&lt;!-- 保存文件的ID --&gt;
        &lt;/c:if&gt;
        &lt;table id="fileInfoTable"&gt;
            &lt;c:forEach items="${list }" var="doc"&gt;
                &lt;tr id='${doc.id }'&gt;
                    &lt;td&gt;${doc.displayName }&lt;/td&gt;
                    &lt;td&gt;
                        &lt;input type='button' onclick='window.open("/viewfile/${doc.id }")'  class='btn btn-primary' value='下载'/&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            &lt;/c:forEach&gt;
       
        &lt;/table&gt;
    &lt;/form:form&gt;
&lt;/body&gt;
&lt;/html&gt;

第二个文件:后台Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package com.thinkgem.jeesite.modules.sys.web;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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 org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;


import com.thinkgem.jeesite.common.utils.FileUploadUtil;
import com.thinkgem.jeesite.common.utils.StringUtils;

/**
 *
 * 文件上传.
 *
 * @author prd
 *
 */
@Controller
@RequestMapping(value = "/")
public class DocumentController {

    @Autowired
    private DocumentService documentService;

    @RequestMapping(value = "uploadFile")
    public String uploadFile(String fileUploadType, String[] fileIds, HttpServletRequest request,
            HttpServletResponse response, Model model) {
        if (null != fileIds &amp;&amp; fileIds.length &gt; 0) {
            Document document = new Document();
            document.setIdQuery(Arrays.asList(fileIds));
            List&lt;Document&gt; documentList = documentService.findList(document);
            model.addAttribute("list", documentList);
        }
        model.addAttribute("fileUploadType", fileUploadType);
        return "files";
    }

    /**
     * 下载文件/查看文件.
     *
     * @param model
     * @param response
     * @param filesId
     */
    @RequestMapping(value = "/viewfile/{filesId}", method = RequestMethod.GET)
    public void viewFile(Model model, HttpServletResponse response, @PathVariable("filesId") String filesId) {
        Document result = documentService.get(filesId);
        if (null != result) { // response 显示.
            FileUploadUtil.viewFile(result.getDisplayName(), result.getFilePath(), response);
        }
    }

    /**
     * 删除文件.
     *
     * @param model
     * @param response
     * @param fileId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "deleteFile")
    public AppJson deleteFile(Model model, HttpServletResponse response, String fileId) {
        if (StringUtils.isNotBlank(fileId)) {
            documentService.delete(fileId);
            return new AppJson("0", "文件删除成功!");
        }
        return new AppJson("1", "文件删除错误:文件ID为空!");
    }

    /**
     * 保存文件.
     *
     *
     * @param document
     * @param request
     * @param response
     * @return
     */
    @ResponseBody
    @RequestMapping(value = { "saveFile" })
    public AppJson saveFile(Document document, HttpServletRequest request, HttpServletResponse response) {
        if (null != document &amp;&amp; StringUtils.isNotBlank(document.getFileUploadType())) {
            List&lt;Document&gt; filePathList = new ArrayList&lt;Document&gt;();
            try {
                filePathList = FileUploadUtil.uploadFile(request, response, document.getFileUploadType());
                if (filePathList.size() &gt; 0) {
                    Document newdocument = filePathList.get(0);
                    final String uuid = IdGen.uuid();
                    newdocument.setId(uuid);
                    documentService.save(newdocument);
                    Document result = new Document();
                    result.setId(uuid);
                    result.setDisplayName(newdocument.getDisplayName());
                    return new AppJson("0", "保存成功", result);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return new AppJson("1", e.getMessage());
            } catch (Exception ex) {
                ex.printStackTrace();
                return new AppJson("1", ex.getMessage());
            }
            if (filePathList.size() == 0) {
                return new AppJson("1", "系统错误!");
            }
        }
        return new AppJson("1", "文件上传类型[fileuploadtype]不能为空!");
    }

}

第三个文件:后台-文件实体Document.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.util.List;


/**
 * 保存文件.
 *
 *
 * @author prd.
 *
 */
public class Document{

    private String id;//数据ID.
    private String fileName; // 文件名.
    private String displayName; // 显示的文件名.
    private String filePath; // 文件保存路径
    private String fileUploadType; // 上传文件的属性:1-&gt;用户.
   
   
    private static final String UPLOADTYPE_USER = "1";//用户.
   
    /**
     * 通过数字来获取上传文件的文件名.
     *
     * @param fileUploadTypeInfo
     * @return
     */
    public static String getTypeName(String fileUploadTypeInfo){
        switch(fileUploadTypeInfo){
        case UPLOADTYPE_USER:
            return "user";
        }      
        return "user";
    }
   
   
    public Document(String fileName, String displayName, String filePath, String fileUploadType) {
        this.fileName = fileName;
        this.displayName = displayName;
        this.filePath = filePath;
        this.fileUploadType = fileUploadType;
    }
   
   
    public Document() {
       
    }

    public String getFileName() {
        return fileName;
    }



    public void setFileName(String fileName) {
        this.fileName = fileName;
    }



    public String getDisplayName() {
        return displayName;
    }



    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }



    public String getFilePath() {
        return filePath;
    }



    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }



    public String getFileUploadType() {
        return fileUploadType;
    }



    public void setFileUploadType(String fileUploadType) {
        this.fileUploadType = fileUploadType;
    }

}

第四个文件:后台-字符串工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/**
 * Copyright &amp;copy; 2012-2014 &lt;a href="https://github.com/thinkgem/jeesite"&gt;JeeSite&lt;/a&gt; All rights reserved.
 */
package com.thinkgem.jeesite.common.utils;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.LocaleResolver;

import com.google.common.collect.Lists;

/**
 * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
 * @author ThinkGem
 * @version 2013-05-22
 */
public class StringUtils extends org.apache.commons.lang3.StringUtils {
   
    private static final char SEPARATOR = '_';
    private static final String CHARSET_NAME = "UTF-8";
   
    /**
     * 转换为字节数组
     * @param str
     * @return
     */
    public static byte[] getBytes(String str){
        if (str != null){
            try {
                return str.getBytes(CHARSET_NAME);
            } catch (UnsupportedEncodingException e) {
                return null;
            }
        }else{
            return null;
        }
    }
   
    /**
     * 转换为字节数组
     * @param str
     * @return
     */
    public static String toString(byte[] bytes){
        try {
            return new String(bytes, CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            return EMPTY;
        }
    }
   
    /**
     * 是否包含字符串
     * @param str 验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inString(String str, String... strs){
        if (str != null){
            for (String s : strs){
                if (str.equals(trim(s))){
                    return true;
                }
            }
        }
        return false;
    }
   
    /**
     * 替换掉HTML标签方法
     */
    public static String replaceHtml(String html) {
        if (isBlank(html)){
            return "";
        }
        String regEx = "&lt;.+?&gt;";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(html);
        String s = m.replaceAll("");
        return s;
    }
   
    /**
     * 替换为手机识别的HTML,去掉样式及属性,保留回车。
     * @param html
     * @return
     */
    public static String replaceMobileHtml(String html){
        if (html == null){
            return "";
        }
        return html.replaceAll("&lt;([a-z]+?)\\s+?.*?&gt;", "&lt;$1&gt;");
    }
   
    /**
     * 替换为手机识别的HTML,去掉样式及属性,保留回车。
     * @param txt
     * @return
     */
    public static String toHtml(String txt){
        if (txt == null){
            return "";
        }
        return replace(replace(Encodes.escapeHtml(txt), "\n", "&lt;br/&gt;"), "\t", "&amp;nbsp; &amp;nbsp; ");
    }

    /**
     * 缩略字符串(不区分中英文字符)
     * @param str 目标字符串
     * @param length 截取长度
     * @return
     */
    public static String abbr(String str, int length) {
        if (str == null) {
            return "";
        }
        try {
            StringBuilder sb = new StringBuilder();
            int currentLength = 0;
            for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) {
                currentLength += String.valueOf(c).getBytes("GBK").length;
                if (currentLength &lt;= length - 3) {
                    sb.append(c);
                } else {
                    sb.append("...");
                    break;
                }
            }
            return sb.toString();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }
   
    public static String abbr2(String param, int length) {
        if (param == null) {
            return "";
        }
        StringBuffer result = new StringBuffer();
        int n = 0;
        char temp;
        boolean isCode = false; // 是不是HTML代码
        boolean isHTML = false; // 是不是HTML特殊字符,如&amp;nbsp;
        for (int i = 0; i &lt; param.length(); i++) {
            temp = param.charAt(i);
            if (temp == '&lt;') {
                isCode = true;
            } else if (temp == '&amp;') {
                isHTML = true;
            } else if (temp == '&gt;' &amp;&amp; isCode) {
                n = n - 1;
                isCode = false;
            } else if (temp == ';' &amp;&amp; isHTML) {
                isHTML = false;
            }
            try {
                if (!isCode &amp;&amp; !isHTML) {
                    n += String.valueOf(temp).getBytes("GBK").length;
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            if (n &lt;= length - 3) {
                result.append(temp);
            } else {
                result.append("...");
                break;
            }
        }
        // 取出截取字符串中的HTML标记
        String temp_result = result.toString().replaceAll("(&gt;)[^&lt;&gt;]*(&lt;?)",
                "$1$2");
        // 去掉不需要结素标记的HTML标记
        temp_result = temp_result
                .replaceAll(
                        "&lt;/?(AREA|BASE|BASEFONT|BODY|BR|COL|COLGROUP|DD|DT|FRAME|HEAD|HR|HTML|IMG|INPUT|ISINDEX|LI|LINK|META|OPTION|P|PARAM|TBODY|TD|TFOOT|TH|THEAD|TR|area|base|basefont|body|br|col|colgroup|dd|dt|frame|head|hr|html|img|input|isindex|li|link|meta|option|p|param|tbody|td|tfoot|th|thead|tr)[^&lt;&gt;]*/?&gt;",
                        "");
        // 去掉成对的HTML标记
        temp_result = temp_result.replaceAll("&lt;([a-zA-Z]+)[^&lt;&gt;]*&gt;(.*?)&lt;/\\1&gt;",
                "$2");
        // 用正则表达式取出标记
        Pattern p = Pattern.compile("&lt;([a-zA-Z]+)[^&lt;&gt;]*&gt;");
        Matcher m = p.matcher(temp_result);
        List&lt;String&gt; endHTML = Lists.newArrayList();
        while (m.find()) {
            endHTML.add(m.group(1));
        }
        // 补全不成对的HTML标记
        for (int i = endHTML.size() - 1; i &gt;= 0; i--) {
            result.append("&lt;/");
            result.append(endHTML.get(i));
            result.append("&gt;");
        }
        return result.toString();
    }
   
    /**
     * 转换为Double类型
     */
    public static Double toDouble(Object val){
        if (val == null){
            return 0D;
        }
        try {
            return Double.valueOf(trim(val.toString()));
        } catch (Exception e) {
            return 0D;
        }
    }

    /**
     * 转换为Float类型
     */
    public static Float toFloat(Object val){
        return toDouble(val).floatValue();
    }

    /**
     * 转换为Long类型
     */
    public static Long toLong(Object val){
        return toDouble(val).longValue();
    }

    /**
     * 转换为Integer类型
     */
    public static Integer toInteger(Object val){
        return toLong(val).intValue();
    }
   
    /**
     * 获得i18n字符串
     */
    public static String getMessage(String code, Object[] args) {
        LocaleResolver localLocaleResolver = (LocaleResolver) SpringContextHolder.getBean(LocaleResolver.class);
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();  
        Locale localLocale = localLocaleResolver.resolveLocale(request);
        return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale);
    }
   
    /**
     * 获得用户远程地址
     */
    public static String getRemoteAddr(HttpServletRequest request){
        String remoteAddr = request.getHeader("X-Real-IP");
        if (isNotBlank(remoteAddr)) {
            remoteAddr = request.getHeader("X-Forwarded-For");
        }else if (isNotBlank(remoteAddr)) {
            remoteAddr = request.getHeader("Proxy-Client-IP");
        }else if (isNotBlank(remoteAddr)) {
            remoteAddr = request.getHeader("WL-Proxy-Client-IP");
        }
        return remoteAddr != null ? remoteAddr : request.getRemoteAddr();
    }

    /**
     * 驼峰命名法工具
     * @return
     *      toCamelCase("hello_world") == "helloWorld"
     *      toCapitalizeCamelCase("hello_world") == "HelloWorld"
     *      toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toCamelCase(String s) {
        if (s == null) {
            return null;
        }

        s = s.toLowerCase();

        StringBuilder sb = new StringBuilder(s.length());
        boolean upperCase = false;
        for (int i = 0; i &lt; s.length(); i++) {
            char c = s.charAt(i);

            if (c == SEPARATOR) {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }

        return sb.toString();
    }

    /**
     * 驼峰命名法工具
     * @return
     *      toCamelCase("hello_world") == "helloWorld"
     *      toCapitalizeCamelCase("hello_world") == "HelloWorld"
     *      toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toCapitalizeCamelCase(String s) {
        if (s == null) {
            return null;
        }
        s = toCamelCase(s);
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }
   
    /**
     * 驼峰命名法工具
     * @return
     *      toCamelCase("hello_world") == "helloWorld"
     *      toCapitalizeCamelCase("hello_world") == "HelloWorld"
     *      toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toUnderScoreCase(String s) {
        if (s == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for (int i = 0; i &lt; s.length(); i++) {
            char c = s.charAt(i);

            boolean nextUpperCase = true;

            if (i &lt; (s.length() - 1)) {
                nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
            }

            if ((i &gt; 0) &amp;&amp; Character.isUpperCase(c)) {
                if (!upperCase || !nextUpperCase) {
                    sb.append(SEPARATOR);
                }
                upperCase = true;
            } else {
                upperCase = false;
            }

            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }
   
    /**
     * 如果不为空,则设置值
     * @param target
     * @param source
     */
    public static void setValueIfNotBlank(String target, String source) {
        if (isNotBlank(source)){
            target = source;
        }
    }
 
    /**
     * 转换为JS获取对象值,生成三目运算返回结果
     * @param objectString 对象串
     *   例如:row.user.id
     *   返回:!row?'':!row.user?'':!row.user.id?'':row.user.id
     */
    public static String jsGetVal(String objectString){
        StringBuilder result = new StringBuilder();
        StringBuilder val = new StringBuilder();
        String[] vals = split(objectString, ".");
        for (int i=0; i&lt;vals.length; i++){
            val.append("." + vals[i]);
            result.append("!"+(val.substring(1))+"?'':");
        }
        result.append(val.substring(1));
        return result.toString();
    }
   
}

第五个文件:后台-日期工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/**
 * Copyright &amp;copy; 2012-2014 &lt;a href="https://github.com/thinkgem/jeesite"&gt;JeeSite&lt;/a&gt; All rights reserved.
 */
package com.thinkgem.jeesite.common.utils;

import java.text.ParseException;
import java.util.Date;

import org.apache.commons.lang3.time.DateFormatUtils;

/**
 * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类
 * @author ThinkGem
 * @version 2014-4-15
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
   
    private static String[] parsePatterns = {
        "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
        "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
        "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 得到当前日期字符串 格式(yyyy-MM-dd)
     */
    public static String getDate() {
        return getDate("yyyy-MM-dd");
    }
   
    /**
     * 得到当前日期字符串 格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
     */
    public static String getDate(String pattern) {
        return DateFormatUtils.format(new Date(), pattern);
    }
   
    /**
     * 得到日期字符串 默认格式(yyyy-MM-dd) pattern可以为:"yyyy-MM-dd" "HH:mm:ss" "E"
     */
    public static String formatDate(Date date, Object... pattern) {
        String formatDate = null;
        if (pattern != null &amp;&amp; pattern.length &gt; 0) {
            formatDate = DateFormatUtils.format(date, pattern[0].toString());
        } else {
            formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
        }
        return formatDate;
    }
   
    /**
     * 得到日期时间字符串,转换格式(yyyy-MM-dd HH:mm:ss)
     */
    public static String formatDateTime(Date date) {
        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 得到当前时间字符串 格式(HH:mm:ss)
     */
    public static String getTime() {
        return formatDate(new Date(), "HH:mm:ss");
    }

    /**
     * 得到当前日期和时间字符串 格式(yyyy-MM-dd HH:mm:ss)
     */
    public static String getDateTime() {
        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 得到当前年份字符串 格式(yyyy)
     */
    public static String getYear() {
        return formatDate(new Date(), "yyyy");
    }

    /**
     * 得到当前月份字符串 格式(MM)
     */
    public static String getMonth() {
        return formatDate(new Date(), "MM");
    }

    /**
     * 得到当天字符串 格式(dd)
     */
    public static String getDay() {
        return formatDate(new Date(), "dd");
    }

    /**
     * 得到当前星期字符串 格式(E)星期几
     */
    public static String getWeek() {
        return formatDate(new Date(), "E");
    }
   
    /**
     * 日期型字符串转化为日期 格式
     * { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
     *   "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm",
     *   "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" }
     */
    public static Date parseDate(Object str) {
        if (str == null){
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取过去的天数
     * @param date
     * @return
     */
    public static long pastDays(Date date) {
        long t = new Date().getTime()-date.getTime();
        return t/(24*60*60*1000);
    }

    /**
     * 获取过去的小时
     * @param date
     * @return
     */
    public static long pastHour(Date date) {
        long t = new Date().getTime()-date.getTime();
        return t/(60*60*1000);
    }
   
    /**
     * 获取过去的分钟
     * @param date
     * @return
     */
    public static long pastMinutes(Date date) {
        long t = new Date().getTime()-date.getTime();
        return t/(60*1000);
    }
   
    /**
     * 转换为时间(天,时:分:秒.毫秒)
     * @param timeMillis
     * @return
     */
    public static String formatDateTime(long timeMillis){
        long day = timeMillis/(24*60*60*1000);
        long hour = (timeMillis/(60*60*1000)-day*24);
        long min = ((timeMillis/(60*1000))-day*24*60-hour*60);
        long s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);
        long sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);
        return (day&gt;0?day+",":"")+hour+":"+min+":"+s+"."+sss;
    }
   
    /**
     * 获取两个日期之间的天数
     *
     * @param before
     * @param after
     * @return
     */
    public static double getDistanceOfTwoDate(Date before, Date after) {
        long beforeTime = before.getTime();
        long afterTime = after.getTime();
        return (afterTime - beforeTime) / (1000 * 60 * 60 * 24);
    }
   
    /**
     * @param args
     * @throws ParseException
     */
    public static void main(String[] args) throws ParseException {
//      System.out.println(formatDate(parseDate("2010/3/6")));
//      System.out.println(getDate("yyyy年MM月dd日 E"));
//      long time = new Date().getTime()-parseDate("2012-11-19").getTime();
//      System.out.println(time/(24*60*60*1000));
    }
}

第六个文件:后台-ID生成工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
 * Copyright &amp;copy; 2012-2014 &lt;a href="https://github.com/thinkgem/jeesite"&gt;JeeSite&lt;/a&gt; All rights reserved.
 */
package com.thinkgem.jeesite.common.utils;

import java.io.Serializable;
import java.security.SecureRandom;
import java.util.UUID;

import org.activiti.engine.impl.cfg.IdGenerator;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

/**
 * 封装各种生成唯一性ID算法的工具类.
 * @author ThinkGem
 * @version 2013-01-15
 */
@Service
@Lazy(false)
public class IdGen implements IdGenerator, SessionIdGenerator {

    private static SecureRandom random = new SecureRandom();
   
    /**
     * 封装JDK自带的UUID, 通过Random数字生成, 中间无-分割.
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
   
    /**
     * 使用SecureRandom随机生成Long.
     */
    public static long randomLong() {
        return Math.abs(random.nextLong());
    }

    /**
     * 基于Base62编码的SecureRandom随机生成bytes.
     */
    public static String randomBase62(int length) {
        byte[] randomBytes = new byte[length];
        random.nextBytes(randomBytes);
        return Encodes.encodeBase62(randomBytes);
    }
   
    /**
     * Activiti ID 生成
     */
    @Override
    public String getNextId() {
        return IdGen.uuid();
    }

    @Override
    public Serializable generateId(Session session) {
        return IdGen.uuid();
    }
   
    public static void main(String[] args) {
        System.out.println(IdGen.uuid());
        System.out.println(IdGen.uuid().length());
        System.out.println(new IdGen().getNextId());
        for (int i=0; i&lt;1000; i++){
            System.out.println(IdGen.randomLong() + "  " + IdGen.randomBase62(5));
        }
    }

}

第七个文件:后台-上传处理Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.File;
import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;



@Service
@Transactional(readOnly = true)
public class DocumentService   {
   
   
    @Transactional(readOnly=false)
    public void save(Document document){
        // codeing...... 保存到数据库
    }
   
   
    public List&lt;Document&gt; findList(Document document){
        // coding...... 从数据库查询数据
        return null ;
    }
   
    @Transactional(readOnly = false)
    public void delete(Document document){
        // coding...... 删除数据
    }
   
    @Transactional(readOnly = false)
    public void delete(String id){
        // coding...... 删除数据
        Document document = null;// TODO 先从数据库获取对象数据
        if(null!=document){
            File file = new File(document.getFilePath()); // 找到文件系统中的文件
            if(file.exists()){ // 文件系统中存在
                file.delete(); // 删除文件系统中的文件.
                //delete(document); // 删除数据库中的数据
            }
        }
    }
   

}

第八个文件:后台-【文件上传处理类】【核心】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

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.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;


/**
 * 上传文件
 * @author scar
 *
 */
public class FileUploadUtil {
   
   
    private static Log log = LogFactory.getLog(FileUploadUtil.class);
    public static List&lt;Document&gt; uploadFile(HttpServletRequest request,
            HttpServletResponse response, String uploadFileType) throws FileNotFoundException{
        List&lt;Document&gt; filePathList = new ArrayList&lt;Document&gt;();
       
        String strPath = ",webapps,files,"+Document.getTypeName(uploadFileType);
       
        String filepath =   strPath.replace(",", "/");
       
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
       
        Map&lt;String, MultipartFile&gt; fileMap = multipartRequest.getFileMap();
        String fileName = null;
        for (Map.Entry&lt;String, MultipartFile&gt; entity : fileMap.entrySet()) {

            MultipartFile mf = entity.getValue();
            fileName = mf.getOriginalFilename();
            String fileType = fileName.substring(fileName.lastIndexOf('.'));
            try {
                String newFileName = MD5FileUtil.getMD5String(mf.getBytes());
                String newfilepath;
                newfilepath = filepath + "/" + newFileName + fileType;

                File dest = new File(filepath);
                if(!dest.exists()){
                    dest.mkdirs();
                }
                File uploadFile = new File(newfilepath);
                if(uploadFile.exists()){
                    uploadFile.delete();
                }
                log.info("start upload file: " + fileName);
                FileCopyUtils.copy(mf.getBytes(), uploadFile);
                Document filesnew = new Document();
                filesnew.setFileUploadType(uploadFileType);
                filesnew.setDisplayName(fileName);
                filesnew.setFileName(newFileName + fileType);
                filesnew.setFilePath(newfilepath);
                filePathList.add(filesnew);

            } catch (IOException e) {
                e.printStackTrace();
                log.info("upload failed. filename: " + fileName + e.getMessage());
                return null;
            }
        }
        return filePathList;
    }
   
    /**
     * 向前台输出文件.
     *
     *
     * @param path
     * @param response
     * @return
     */
    public static HttpServletResponse download(String path, HttpServletResponse response) {
        try {
            // path是指欲下载的文件的路径。
            File file = new File(path);
            // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            //String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();

            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            response.addHeader("Content-Length", "" + file.length());
            response.setContentType("multipart/form-data");  
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return response;
    }
   
   
    /**
     * 向前台输出文件.
     *
     *
     * @param path
     * @param response
     * @return
     */
    public static HttpServletResponse viewFile(String fileDisplayName,String path, HttpServletResponse response) {
        try {
            // path是指欲下载的文件的路径。
            File file = new File(path);
           /* // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();*/

            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileDisplayName.getBytes()));
            response.addHeader("Content-Length", "" + file.length());
            String contentType = java.nio.file.Files.probeContentType(Paths.get(path));
            System.out.println("contentType:"+contentType);
            response.setContentType(contentType);  
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return response;
    }
}

看完着实不易…到此.

Struts:第一个小程序

崎岖的诞生过程

说明一下,这并非是说代码难敲什么的。从昨晚敲完书本上的代码后,一直就不能正常的测试!!!觉得有点迷茫,甚至有点灰心。。。可是,可是,转念一想,这不是长姿势的好机会么?于是,慢慢找答案吧。

OK!回到正题,简单说说我遇到的几个错误,以及解决方案.

小应用简述

这是一个登陆验证的特别简单的例子,共有以下几个配置文件:

  1. 登陆页:index.jsp
  2. 欢迎页:welcome.jsp
  3. Action:LoginAction

这个例子就是从登陆页输入用户名和密码,然后发送至Action处理,如果用户名和密码正确,则跳转到weclome.jsp页面,否则留在index.jsp页面.

Struts logo
image-1946

struts2 action class not found

这是我使用的搜索词,大致意思是:当表单提交的时候,访问不了Action…这可苦逼了,第一次配置Struts就遇到这事,心中难免失落……不过也不能不做啊!于是找各种答案,各种尝试,反正就是访问不了.

其实解决方案并不是很难,在提交表单的时候写成下面这个样子就行了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
<s:form action="action_struts/loginA.action" method="post"><!-- 写成loginA或者loginA.action都是不能的 -->
    <s:label value="登录信息"></s:label>
    <s:textfield name="username" label="用户名"></s:textfield>
    <s:password name="userpass" label="密码"></s:password>
    <s:submit value="登录"></s:submit>
</s:form>
</body>
</html>

Struts2 抛 java.lang.NoSuchMethodException

这个方法指的是找不到指定的方法,所以抛出这个异常。

抛出这个异常的原因是,下面这段代码写成这样了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
    "http://struts.apache.org/dtds/struts-2.1.dtd">
    <struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <!-- 2013.8.16  -->
        <package name="first" extends="struts-default" namespace="/N12"><!-- 定义一个package -->
            <!-- 对action返回结果的配置 -->
            <action name="loginA" class="action_struts.LoginAction" method="{1}"  ><!--这一句多余: method="{1}"  -->
                <result name="success">/welcome.jsp</result>
                <result name="login">/index.jsp</result>
            </action>
        </package>
        <!-- END 2013.8.16 -->
    </struts>

重复的action

这个问题我还没有找到解决办法,具体错误如下:每成功的登录一次,URL中就会重复一次[Action类所在包的包名,例如包名是:actions],那么每登录成功一次,包名就会多一个.
形如:

1
localhost:8080/TEST/A10/actions/[actions...+]/LoginAction.action

完整的代码

测试可用.
系统环境如下:

  • tomcat 7.0.35
  • Eclipse 4.2
  • struts 2
  • jdk 1.7

index.jsp[首页][所在文件夹:WebContent]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>

<s:form action="action_struts/loginA.action" method="post">
    <s:label value="登录信息"></s:label>
    <s:textfield name="username" label="用户名"></s:textfield>
    <s:password name="userpass" label="密码"></s:password>
    <s:submit value="登录"></s:submit>
</s:form>
</body>
</html>

welcome.jsp[欢迎页][所在文件夹:WebContent]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8" ?>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
登录成功,欢迎您,<s:property value="username" /><!-- 显示Action中的username属性 -->
</body>
</html>

struts.xml[struts核心配置文件][所在文件夹:WebContent/WEB-INF/classes/]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
    "http://struts.apache.org/dtds/struts-2.1.dtd">
    <struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <!-- 2013.8.16  -->
        <package name="first" extends="struts-default" namespace="/"><!-- 定义一个package -->
            <!-- 对action返回结果的配置 -->
            <action name="loginA" class="action_struts.LoginAction"  >
                <result name="success">/welcome.jsp</result>
                <result name="login">/index.jsp</result>
            </action>
        </package>
        <!-- END 2013.8.16 -->
    </struts>

web.xm[所在文件夹:WebContent/WEB-INF/]l:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
    id="WebApp_ID" version="3.0">  
    <display-name>SSH</display-name>  
    <welcome-file-list>  
        <welcome-file>index.jsp</welcome-file>  
    </welcome-file-list>  
 
    <filter>  
        <filter-name>struts2</filter-name>  
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>  
    </filter>  
 
    <filter-mapping>  
        <filter-name>struts2</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
</web-app>

Action:LoginAction.java[Java Resources:src>[package:action_struts]]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package action_struts;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {
   
    private String username ;//用户名
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getUserpass() {
        return userpass;
    }
    public void setUserpass(String userpass) {
        this.userpass = userpass;
    }
    private String userpass ;//密码.
   
    public String execute(){//主方法
        if("mr".equalsIgnoreCase(username)&& "123".equals(userpass)){//匹配用户名和密码
            return SUCCESS;//匹配成功进入欢迎界面.
        }
        return LOGIN;//匹配失败进入登录界面
    }

}

struts的jar包请放在WebContent/WEB-INF/lib/文件夹内,我是导入了所有jar包.
一切弄好之后:打开浏览器,输入[localhost:8080/[项目名]/index.jsp],就能测试了[用户名:mr,密码:123].

继续前行,COM ON!~