我想在我的应用程序中添加一个Spring Boot和Thymeleaf的联系表单示例。
我在GitHub上跟随了这个例子:thymeleafexamples-springmail
用于配置邮件发件人的 SpringMailConfig 类。
import java.io.IOException;
import java.util.Collections;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.mail.javamail.JavaMailSender;
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;
//Configure a Mail Sender object
@Configuration
@PropertySource("classpath:mail/emailconfig.properties")
public class SpringMailConfig implements ApplicationContextAware, EnvironmentAware {
public static final String EMAIL_TEMPLATE_ENCODING = "UTF-8";
private static final String JAVA_MAIL_FILE = "classpath:mail/javamail.properties";
private static final String HOST = "mail.server.host";
private static final String PORT = "mail.server.port";
private static final String PROTOCOL = "mail.server.protocol";
private static final String USERNAME = "mail.server.username";
private static final String PASSWORD = "mail.server.password";
private ApplicationContext applicationContext;
private Environment environment;
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setEnvironment(final Environment environment) {
this.environment = environment;
}
/*
* SPRING + JAVAMAIL: JavaMailSender instance, configured via .properties files.
*/
@Bean
public JavaMailSender mailSender() throws IOException {
final JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
// Basic mail sender configuration, based on emailconfig.properties
mailSender.setHost(this.environment.getProperty(HOST));
mailSender.setPort(Integer.parseInt(this.environment.getProperty(PORT)));
mailSender.setProtocol(this.environment.getProperty(PROTOCOL));
mailSender.setUsername(this.environment.getProperty(USERNAME));
mailSender.setPassword(this.environment.getProperty(PASSWORD));
// JavaMail-specific mail sender configuration, based on javamail.properties
final Properties javaMailProperties = new Properties();
javaMailProperties.load(this.applicationContext.getResource(JAVA_MAIL_FILE).getInputStream());
mailSender.setJavaMailProperties(javaMailProperties);
return mailSender;
}
@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(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(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;
}
}
发送邮件的 EmailService 类:
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import com.example.springmail.configuration.SpringMailConfig;
//Service to send mails
@Service
public class EmailService {
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 = "classpath:mail/editablehtml/email-editable.html";
private static final String BACKGROUND_IMAGE = "mail/editablehtml/images/background.png";
private static final String LOGO_BACKGROUND_IMAGE = "mail/editablehtml/images/logo-background.png";
private static final String THYMELEAF_BANNER_IMAGE = "mail/editablehtml/images/thymeleaf-banner.png";
private static final String THYMELEAF_LOGO_IMAGE = "mail/editablehtml/images/thymeleaf-logo.png";
private static final String PNG_MIME = "image/png";
@Autowired
private ApplicationContext applicationContext;
@Autowired
private JavaMailSender mailSender;
@Autowired
private TemplateEngine htmlTemplateEngine;
@Autowired
private TemplateEngine textTemplateEngine;
@Autowired
private TemplateEngine stringTemplateEngine;
/*
* Send plain TEXT mail
*/
public void sendTextMail(
final String recipientName, final String recipientEmail, final Locale locale)
throws MessagingException {
// Prepare the evaluation context
final Context ctx = new Context(locale);
ctx.setVariable("name", recipientName);
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");
message.setSubject("Example plain TEXT email");
message.setFrom("thymeleaf@example.com");
message.setTo(recipientEmail);
// Create the plain TEXT body using Thymeleaf
final String textContent = this.textTemplateEngine.process(EMAIL_TEXT_TEMPLATE_NAME, ctx);
message.setText(textContent);
// Send email
this.mailSender.send(mimeMessage);
}
/*
* Send HTML mail (simple)
*/
public void sendSimpleMail(
final String recipientName, final String recipientEmail, final Locale locale)
throws MessagingException {
// Prepare the evaluation context
final Context ctx = new Context(locale);
ctx.setVariable("name", recipientName);
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");
message.setSubject("Example HTML email (simple)");
message.setFrom("thymeleaf@example.com");
message.setTo(recipientEmail);
// Create the HTML body using Thymeleaf
final String htmlContent = this.htmlTemplateEngine.process(EMAIL_SIMPLE_TEMPLATE_NAME, ctx);
message.setText(htmlContent, true /* isHtml */);
// Send email
this.mailSender.send(mimeMessage);
}
/*
* Send HTML mail with attachment.
*/
public void sendMailWithAttachment(
final String recipientName, final String recipientEmail, final String attachmentFileName,
final byte[] attachmentBytes, final String attachmentContentType, final Locale locale)
throws MessagingException {
// Prepare the evaluation context
final Context ctx = new Context(locale);
ctx.setVariable("name", recipientName);
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, true /* multipart */, "UTF-8");
message.setSubject("Example HTML email with attachment");
message.setFrom("thymeleaf@example.com");
message.setTo(recipientEmail);
// Create the HTML body using Thymeleaf
final String htmlContent = this.htmlTemplateEngine.process(EMAIL_WITHATTACHMENT_TEMPLATE_NAME, ctx);
message.setText(htmlContent, true /* isHtml */);
// Add the attachment
final InputStreamSource attachmentSource = new ByteArrayResource(attachmentBytes);
message.addAttachment(
attachmentFileName, attachmentSource, attachmentContentType);
// Send mail
this.mailSender.send(mimeMessage);
}
/*
* Send HTML mail with inline image
*/
public void sendMailWithInline(
final String recipientName, final String recipientEmail, final String imageResourceName,
final byte[] imageBytes, final String imageContentType, final Locale locale)
throws MessagingException {
// Prepare the evaluation context
final Context ctx = new Context(locale);
ctx.setVariable("name", recipientName);
ctx.setVariable("subscriptionDate", new Date());
ctx.setVariable("hobbies", Arrays.asList("Cinema", "Sports", "Music"));
ctx.setVariable("imageResourceName", imageResourceName); // so that we can reference it from HTML
// Prepare message using a Spring helper
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message
= new MimeMessageHelper(mimeMessage, true /* multipart */, "UTF-8");
message.setSubject("Example HTML email with inline image");
message.setFrom("thymeleaf@example.com");
message.setTo(recipientEmail);
// Create the HTML body using Thymeleaf
final String htmlContent = this.htmlTemplateEngine.process(EMAIL_INLINEIMAGE_TEMPLATE_NAME, ctx);
message.setText(htmlContent, true /* isHtml */);
// Add the inline image, referenced from the HTML code as "cid:${imageResourceName}"
final InputStreamSource imageSource = new ByteArrayResource(imageBytes);
message.addInline(imageResourceName, imageSource, imageContentType);
// Send mail
this.mailSender.send(mimeMessage);
}
/*
* Send HTML mail with inline image
*/
public String getEditableMailTemplate() throws IOException {
final Resource templateResource = this.applicationContext.getResource(EMAIL_EDITABLE_TEMPLATE_CLASSPATH_RES);
final InputStream inputStream = templateResource.getInputStream();
return IOUtils.toString(inputStream, SpringMailConfig.EMAIL_TEMPLATE_ENCODING);
}
/*
* Send HTML mail with inline image
*/
public void sendEditableMail(
final String recipientName, final String recipientEmail, final String htmlContent,
final Locale locale)
throws MessagingException {
// Prepare message using a Spring helper
final MimeMessage mimeMessage = this.mailSender.createMimeMessage();
final MimeMessageHelper message
= new MimeMessageHelper(mimeMessage, true /* multipart */, "UTF-8");
message.setSubject("Example editable HTML email");
message.setFrom("thymeleaf@example.com");
message.setTo(recipientEmail);
// Prepare the evaluation context
final Context ctx = new Context(locale);
ctx.setVariable("name", recipientName);
ctx.setVariable("subscriptionDate", new Date());
ctx.setVariable("hobbies", Arrays.asList("Cinema", "Sports", "Music"));
// Create the HTML body using Thymeleaf
final String output = stringTemplateEngine.process(htmlContent, ctx);
message.setText(output, true /* isHtml */);
// Add the inline images, referenced from the HTML code as "cid:image-name"
message.addInline("background", new ClassPathResource(BACKGROUND_IMAGE), PNG_MIME);
message.addInline("logo-background", new ClassPathResource(LOGO_BACKGROUND_IMAGE), PNG_MIME);
message.addInline("thymeleaf-banner", new ClassPathResource(THYMELEAF_BANNER_IMAGE), PNG_MIME);
message.addInline("thymeleaf-logo", new ClassPathResource(THYMELEAF_LOGO_IMAGE), PNG_MIME);
// Send mail
this.mailSender.send(mimeMessage);
}
}
调用服务以发送邮件的 SendingController 类:
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.io.IOException;
import java.util.Locale;
import javax.mail.MessagingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.example.springmail.service.EmailService;
//Controller method that calls the service to send mails
@Controller
public class SendingController {
@Autowired
private EmailService emailService;
/* Send plain TEXT mail */
@RequestMapping(value = "/sendMailText", method = POST)
public String sendTextMail(
@RequestParam("recipientName") final String recipientName,
@RequestParam("recipientEmail") final String recipientEmail,
final Locale locale)
throws MessagingException {
this.emailService.sendTextMail(recipientName, recipientEmail, locale);
return "redirect:sent.html";
}
/* Send HTML mail (simple) */
@RequestMapping(value = "/sendMailSimple", method = POST)
public String sendSimpleMail(
@RequestParam("recipientName") final String recipientName,
@RequestParam("recipientEmail") final String recipientEmail,
final Locale locale)
throws MessagingException {
this.emailService.sendSimpleMail(recipientName, recipientEmail, locale);
return "redirect:sent.html";
}
/* Send HTML mail with attachment. */
@RequestMapping(value = "/sendMailWithAttachment", method = POST)
public String sendMailWithAttachment(
@RequestParam("recipientName") final String recipientName,
@RequestParam("recipientEmail") final String recipientEmail,
@RequestParam("attachment") final MultipartFile attachment,
final Locale locale)
throws MessagingException, IOException {
this.emailService.sendMailWithAttachment(
recipientName, recipientEmail, attachment.getOriginalFilename(),
attachment.getBytes(), attachment.getContentType(), locale);
return "redirect:sent.html";
}
/* Send HTML mail with inline image */
@RequestMapping(value = "/sendMailWithInlineImage", method = POST)
public String sendMailWithInline(
@RequestParam("recipientName") final String recipientName,
@RequestParam("recipientEmail") final String recipientEmail,
@RequestParam("image") final MultipartFile image,
final Locale locale)
throws MessagingException, IOException {
this.emailService.sendMailWithInline(
recipientName, recipientEmail, image.getName(),
image.getBytes(), image.getContentType(), locale);
return "redirect:sent.html";
}
/* Send editable HTML mail */
@RequestMapping(value = "/sendEditableMail", method = POST)
public String sendMailWithInline(
@RequestParam("recipientName") final String recipientName,
@RequestParam("recipientEmail") final String recipientEmail,
@RequestParam("body") final String body,
final Locale locale)
throws MessagingException, IOException {
this.emailService.sendEditableMail(
recipientName, recipientEmail, body, locale);
return "redirect:sent.html";
}
}
但我无法启动该应用程序。
申请失败
说明
字段htmlTemplateEngine in com.example.springmail.service.EmailService需要一个bean, 但发现了2个: - emailTemplateEngine:由方法' emailTemplateEngine'定义。在类路径资源中 [COM /示例/ springmail /配置/ SpringMailConfig.class] - templateEngine:由方法' templateEngine'定义。在类路径资源[com / example / springmail / web / SpringWebConfig.class]
中动作:
考虑将其中一个bean标记为@Primary,更新消费者 接受多个bean,或使用@Qualifier来识别bean 应该消费
我有其他类配置可能会导致此问题。
我在另一个问题上发现了同样的问题,但它对我不起作用。 Consider marking one of the beans as @Primary
如何在我的案例中使用 @Primary 和 @Qualifier 注释?
Spring MVC和Thymeleaf配置的 WebMvcConfig 类:
@Configuration
@ComponentScan
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
@Autowired
private ErrorAttributes errorAttributes;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
@Bean
public AppErrorController appErrorController() {
return new AppErrorController(errorAttributes);
}
@Bean
public ResourceBundleMessageSource messageSource() {
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("Messages");
return messageSource;
}
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/*
* Multipart resolver (needed for uploading attachments from web form)
*/
@Bean
public MultipartResolver multipartResolver() {
final CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(10485760); // 10MBytes
return multipartResolver;
}
/* **************************************************************** */
/* THYMELEAF-SPECIFIC ARTIFACTS */
/* TemplateResolver <- TemplateEngine <- ViewResolver */
/* **************************************************************** */
@Bean
public SpringResourceTemplateResolver templateResolver() {
// SpringResourceTemplateResolver automatically integrates with Spring's
// own
// resource resolution infrastructure, which is highly recommended.
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
// HTML is the default value, added here for the sake of clarity.
templateResolver.setTemplateMode(TemplateMode.HTML);
// Template cache is true by default. Set to false if you want
// templates to be automatically updated when modified.
templateResolver.setCacheable(true);
return templateResolver;
}
//problem
@Bean
public SpringTemplateEngine templateEngine() {
// SpringTemplateEngine automatically applies SpringStandardDialect and
// enables Spring's own MessageSource message resolution mechanisms.
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
// Enabling the SpringEL compiler with Spring 4.2.4 or newer can
// speed up execution in most scenarios, but might be incompatible
// with specific cases when expressions in one template are reused
// across different data types, so this flag is "false" by default
// for safer backwards compatibility.
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
}
问题出在emailTemplateEngine()和templateEngine()Beans上。
这是弹簧元素的架构可能会更好地帮助理解问题。
templateEngine Bean:
@Bean
public SpringTemplateEngine templateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
emailTemplateEngine Bean:
@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;
}
Spring boot还有一个用于TemplateEngine的bean:
组织/ springframework的/引导/自动配置/ thymeleaf / ThymeleafAutoConfiguration $ ThymeleafDefaultConfiguration.class
我无法使用@Primary注释或@Qualifier。