{"id":1206,"date":"2025-03-24T08:52:36","date_gmt":"2025-03-23T23:52:36","guid":{"rendered":"https:\/\/dexall.co.jp\/articles\/?p=1206"},"modified":"2025-03-24T08:52:36","modified_gmt":"2025-03-23T23:52:36","slug":"%e3%80%902024%e5%b9%b4%e6%9c%80%e6%96%b0%e3%80%91vaadin%e3%81%a7%e5%ae%9f%e7%8f%be%e3%81%99%e3%82%8b%e9%ab%98%e9%80%9fweb%e9%96%8b%e7%99%ba%e5%85%a5%e9%96%80-java%e9%96%8b%e7%99%ba%e8%80%85%e3%81%ae","status":"publish","type":"post","link":"https:\/\/dexall.co.jp\/articles\/?p=1206","title":{"rendered":"\u30102024\u5e74\u6700\u65b0\u3011Vaadin\u3067\u5b9f\u73fe\u3059\u308b\u9ad8\u901fWeb\u958b\u767a\u5165\u9580 &#8211; Java\u958b\u767a\u8005\u306e\u305f\u3081\u306e\u5c0e\u5165\u30ac\u30a4\u30c9"},"content":{"rendered":"\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>116<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>121<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>128<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\" data-dialog-title=\"\u76ee\u6b21\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">  <li class=\"first\">    <a href=\"#i-0\">Vaadin\u3068\u306f\uff1fJava\u30a8\u30f3\u30b8\u30cb\u30a2\u304c\u6ce8\u76ee\u3059\u3079\u304d\u7406\u7531<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-1\">\u7d14\u7c8b\u306aJava\u3067Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u958b\u767a\u3067\u304d\u308b\u9769\u65b0\u7684\u306a\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af<\/a>      <\/li>      <li>        <a href=\"#i-2\">HTML\/CSS\/JavaScript\u306e\u77e5\u8b58\u306a\u3057\u3067\u30d7\u30ed\u7d1a\u306eUI\u3092\u5b9f\u73fe<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-3\">Spring Boot\u3068\u306e\u5b8c\u74a7\u306a\u7d71\u5408\u306b\u3088\u308b\u30a8\u30b3\u30b7\u30b9\u30c6\u30e0\u306e\u6d3b\u7528<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-4\">Vaadin\u306e\u7279\u5fb4\u3068\u4e3b\u8981\u6a5f\u80fd\u3092\u5fb9\u5e95\u89e3\u8aac<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-5\">\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u30d9\u30fc\u30b9\u306e\u76f4\u611f\u7684\u306aUI\u958b\u767a<\/a>      <\/li>      <li>        <a href=\"#i-6\">\u30c7\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306b\u3088\u308b\u52b9\u7387\u7684\u306a\u30c7\u30fc\u30bf\u7ba1\u7406<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-7\">\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u30c7\u30b6\u30a4\u30f3\u306e\u81ea\u52d5\u30b5\u30dd\u30fc\u30c8<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-8\">Vaadin\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u59cb\u3081\u65b9\uff1a\u74b0\u5883\u69cb\u7bc9\u304b\u3089Hello World\u307e\u3067<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-9\">\u958b\u767a\u74b0\u5883\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u624b\u9806<\/a>      <\/li>      <li>        <a href=\"#i-10\">\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e\u3068\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-11\">\u6700\u521d\u306eVaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u4f5c\u6210<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-12\">\u5b9f\u8df5\u7684\u306aVaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u30ac\u30a4\u30c9<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-13\">\u30d5\u30a9\u30fc\u30e0\u4f5c\u6210\u3068\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u5b9f\u88c5\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/a>      <\/li>      <li>        <a href=\"#i-14\">\u30b0\u30ea\u30c3\u30c9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u4f7f\u7528\u3057\u305f\u30c7\u30fc\u30bf\u8868\u793a\u3068\u64cd\u4f5c<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-15\">\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\u3068\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-16\">Vaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u672c\u756a\u74b0\u5883\u3078\u306e\u5c55\u958b<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-17\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30c6\u30af\u30cb\u30c3\u30af<\/a>      <\/li>      <li>        <a href=\"#i-18\">\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-19\">\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u30d7\u30ed\u30bb\u30b9\u3068\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/a>      <\/li>    <\/ul>  <\/li>  <li class=\"last\">    <a href=\"#i-20\">Vaadin\u3092\u4f7f\u7528\u3057\u305f\u958b\u767a\u306e\u5b9f\u4f8b\u3068\u30b1\u30fc\u30b9\u30b9\u30bf\u30c7\u30a3<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-21\">\u4f01\u696d\u306e\u696d\u52d9\u30b7\u30b9\u30c6\u30e0\u3078\u306e\u5c0e\u5165\u4e8b\u4f8b<\/a>      <\/li>      <li>        <a href=\"#i-22\">EC\u30b5\u30a4\u30c8\u958b\u767a\u3067\u306eVaadin\u306e\u6d3b\u7528\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-23\">\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u3067\u306e\u7d71\u5408\u4f8b<\/a>      <\/li>    <\/ul>  <\/li><\/ul>\n      <a href=\"#\" class=\"sgb-toc-button js-toc-button\" rel=\"nofollow\" data-open-dialog=\"true\"><i class=\"fa fa-list\"><\/i><span class=\"sgb-toc-button__text\">\u76ee\u6b21\u3078<\/span><\/a>\n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-0\">Vaadin\u3068\u306f\uff1fJava\u30a8\u30f3\u30b8\u30cb\u30a2\u304c\u6ce8\u76ee\u3059\u3079\u304d\u7406\u7531<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-1\">\u7d14\u7c8b\u306aJava\u3067Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u958b\u767a\u3067\u304d\u308b\u9769\u65b0\u7684\u306a\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306f\u3001Java\u30a8\u30f3\u30b8\u30cb\u30a2\u306b\u3068\u3063\u3066\u753b\u671f\u7684\u306aWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3059\u3002\u6700\u5927\u306e\u7279\u5fb4\u306f\u3001\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u306e\u958b\u767a\u3092\u3059\u3079\u3066Java\u3067\u884c\u3048\u308b\u3053\u3068\u3067\u3059\u3002\u5f93\u6765\u306eWeb\u958b\u767a\u3067\u306f\u3001\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u306bJava\u3001\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u306bHTML\/CSS\/JavaScript\u3068\u3044\u3046\u6280\u8853\u30b9\u30bf\u30c3\u30af\u306e\u5206\u65ad\u304c\u5b58\u5728\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001Vaadin\u306f\u3053\u306e\u8ab2\u984c\u3092\u89e3\u6c7a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u958b\u767a\u8005\u306f\u7d14\u7c8b\u306aJava\u30b3\u30fc\u30c9\u3092\u8a18\u8ff0\u3059\u308b\u3060\u3051\u3067\u3001Vaadin\u304c\u81ea\u52d5\u7684\u306b\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u30b5\u30a4\u30c9\u306eJavaScript\u30b3\u30fc\u30c9\u306b\u5909\u63db\u3057\u3066\u304f\u308c\u307e\u3059\u3002\u4f8b\u3048\u3070\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u30b7\u30f3\u30d7\u30eb\u306a\u30b3\u30fc\u30c9\u3067\u3001\u30ea\u30a2\u30af\u30c6\u30a3\u30d6\u306aWeb\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u4f5c\u6210\u3067\u304d\u307e\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"\")\npublic class MainView extends VerticalLayout {\n    public MainView() {\n        TextField name = new TextField(\"\u540d\u524d\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\");\n        Button greetButton = new Button(\"\u6328\u62f6\u3059\u308b\");\n        Text greeting = new Text(\"\");\n\n        greetButton.addClickListener(e -&gt; \n            greeting.setText(\"\u3053\u3093\u306b\u3061\u306f\u3001\" + name.getValue() + \"\u3055\u3093\uff01\"));\n\n        add(name, greetButton, greeting);\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-2\">HTML\/CSS\/JavaScript\u306e\u77e5\u8b58\u306a\u3057\u3067\u30d7\u30ed\u7d1a\u306eUI\u3092\u5b9f\u73fe<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306b\u306f\u8c4a\u5bcc\u306aUI\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u30e9\u30a4\u30d6\u30e9\u30ea\u304c\u7528\u610f\u3055\u308c\u3066\u304a\u308a\u3001\u3053\u308c\u3089\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u3060\u3051\u3067\u30e2\u30c0\u30f3\u306aWeb\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u69cb\u7bc9\u3067\u304d\u307e\u3059\u3002\u63d0\u4f9b\u3055\u308c\u308b\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306b\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u3082\u306e\u304c\u3042\u308a\u307e\u3059\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Forms &amp; Data Entry<\/li>\n\n\n\n<li>TextField, TextArea, NumberField<\/li>\n\n\n\n<li>DatePicker, TimePicker<\/li>\n\n\n\n<li>ComboBox, Select<\/li>\n\n\n\n<li>Data Display<\/li>\n\n\n\n<li>Grid\uff08\u9ad8\u6a5f\u80fd\u30c7\u30fc\u30bf\u30c6\u30fc\u30d6\u30eb\uff09<\/li>\n\n\n\n<li>Tree Grid<\/li>\n\n\n\n<li>Charts &amp; Graphs<\/li>\n\n\n\n<li>Layouts<\/li>\n\n\n\n<li>Responsive layouts<\/li>\n\n\n\n<li>CSS Grid<\/li>\n\n\n\n<li>Flex layouts<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306f\u3001\u30de\u30c6\u30ea\u30a2\u30eb\u30c7\u30b6\u30a4\u30f3\u306b\u57fa\u3065\u3044\u305f\u7f8e\u3057\u3044\u30b9\u30bf\u30a4\u30ea\u30f3\u30b0\u304c\u9069\u7528\u6e08\u307f\u3067\u3001\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u5bfe\u5fdc\u3082\u6a19\u6e96\u3067\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3082\u5bb9\u6613\u3067\u3001Lumo theme\u3092\u901a\u3058\u3066\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u5168\u4f53\u306e\u30eb\u30c3\u30af\uff06\u30d5\u30a3\u30fc\u30eb\u3092\u7d71\u4e00\u7684\u306b\u7ba1\u7406\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-3\">Spring Boot\u3068\u306e\u5b8c\u74a7\u306a\u7d71\u5408\u306b\u3088\u308b\u30a8\u30b3\u30b7\u30b9\u30c6\u30e0\u306e\u6d3b\u7528<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306fSpring Boot\u3068\u7dca\u5bc6\u306b\u7d71\u5408\u3055\u308c\u3066\u304a\u308a\u3001Spring Boot\u306e\u30a8\u30b3\u30b7\u30b9\u30c6\u30e0\u3092\u30d5\u30eb\u6d3b\u7528\u3067\u304d\u308b\u3053\u3068\u3082\u5927\u304d\u306a\u9b45\u529b\u3067\u3059\u3002\u4ee5\u4e0b\u306f\u4e3b\u306a\u7d71\u5408\u30dd\u30a4\u30f3\u30c8\u3067\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4f9d\u5b58\u6027\u7ba1\u7406\u306e\u7c21\u7d20\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;dependency&gt;\n    &lt;groupId&gt;com.vaadin&lt;\/groupId&gt;\n    &lt;artifactId&gt;vaadin-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;version&gt;${vaadin.version}&lt;\/version&gt;\n&lt;\/dependency&gt;<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Spring Security\u3068\u306e\u9023\u643a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(value = \"secured\", layout = MainLayout.class)\n@Secured(\"ROLE_ADMIN\")\npublic class SecuredView extends VerticalLayout {\n    public SecuredView() {\n        add(new Text(\"\u7ba1\u7406\u8005\u5c02\u7528\u30da\u30fc\u30b8\u3067\u3059\"));\n    }\n}<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Spring Data JPA\u7b49\u3068\u306e\u9023\u643a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Service\npublic class UserService {\n    @Autowired\n    private UserRepository repository;\n\n    public Grid&lt;User&gt; createUserGrid() {\n        Grid&lt;User&gt; grid = new Grid&lt;&gt;(User.class);\n        grid.setItems(repository.findAll());\n        return grid;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u306e\u3088\u3046\u306b\u3001Vaadin\u3068Spring Boot\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u3001\u30c7\u30fc\u30bf\u30a2\u30af\u30bb\u30b9\u3001DI\uff08\u4f9d\u5b58\u6027\u6ce8\u5165\uff09\u306a\u3069\u306e\u6a5f\u80fd\u3092\u3001\u4e00\u8cab\u3057\u305fJava\u306e\u30b3\u30fc\u30c9\u30d9\u30fc\u30b9\u3067\u5b9f\u88c5\u3067\u304d\u307e\u3059\u3002\u3053\u308c\u306b\u3088\u308a\u3001\u958b\u767a\u52b9\u7387\u306e\u5411\u4e0a\u3068\u30b3\u30fc\u30c9\u306e\u4fdd\u5b88\u6027\u5411\u4e0a\u3092\u540c\u6642\u306b\u9054\u6210\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u7279\u306b\u6ce8\u76ee\u3059\u3079\u304d\u70b9\u3068\u3057\u3066\u3001Spring Boot\u306eAuto-configuration\u306b\u3088\u3063\u3066\u3001\u591a\u304f\u306e\u8a2d\u5b9a\u304c\u81ea\u52d5\u7684\u306b\u884c\u308f\u308c\u308b\u305f\u3081\u3001\u958b\u767a\u8005\u306f\u672c\u8cea\u7684\u306a\u30d3\u30b8\u30cd\u30b9\u30ed\u30b8\u30c3\u30af\u306e\u5b9f\u88c5\u306b\u96c6\u4e2d\u3067\u304d\u307e\u3059\u3002\u307e\u305f\u3001Spring Boot\u306e\u8c4a\u5bcc\u306a\u30b9\u30bf\u30fc\u30bf\u30fc\u30d1\u30c3\u30b1\u30fc\u30b8\u3092\u5229\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u69d8\u3005\u306a\u6a5f\u80fd\u62e1\u5f35\u3082\u5bb9\u6613\u306b\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-4\">Vaadin\u306e\u7279\u5fb4\u3068\u4e3b\u8981\u6a5f\u80fd\u3092\u5fb9\u5e95\u89e3\u8aac<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-5\">\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u30d9\u30fc\u30b9\u306e\u76f4\u611f\u7684\u306aUI\u958b\u767a<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306e\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u30d9\u30fc\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u306f\u3001\u30e2\u30c0\u30f3\u306aWeb\u958b\u767a\u306e\u8003\u3048\u65b9\u3092\u5b8c\u5168\u306b\u53d6\u308a\u5165\u308c\u3066\u3044\u307e\u3059\u3002\u5404UI\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306f\u72ec\u7acb\u3057\u305f\u518d\u5229\u7528\u53ef\u80fd\u306a\u30e6\u30cb\u30c3\u30c8\u3068\u3057\u3066\u6a5f\u80fd\u3057\u3001\u3053\u308c\u3089\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u8907\u96d1\u306a\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u69cb\u7bc9\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u4ee5\u4e0b\u306f\u3001\u5178\u578b\u7684\u306a\u30d5\u30a9\u30fc\u30e0\u4f5c\u6210\u306e\u4f8b\u3067\u3059\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"contact-form\")\npublic class ContactForm extends VerticalLayout {\n    public ContactForm() {\n        \/\/ \u30d5\u30a9\u30fc\u30e0\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u4f5c\u6210\n        TextField name = new TextField(\"\u304a\u540d\u524d\");\n        EmailField email = new EmailField(\"\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\");\n        TextArea message = new TextArea(\"\u30e1\u30c3\u30bb\u30fc\u30b8\");\n        Button submit = new Button(\"\u9001\u4fe1\");\n\n        \/\/ \u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u306e\u8ffd\u52a0\n        name.setRequired(true);\n        name.setMinLength(2);\n        email.setRequired(true);\n\n        \/\/ \u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u8a2d\u5b9a\n        setMaxWidth(\"600px\");\n        setPadding(true);\n        setSpacing(true);\n\n        \/\/ \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u8ffd\u52a0\n        add(\n            new H2(\"\u304a\u554f\u3044\u5408\u308f\u305b\u30d5\u30a9\u30fc\u30e0\"),\n            name,\n            email,\n            message,\n            submit\n        );\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-6\">\u30c7\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306b\u3088\u308b\u52b9\u7387\u7684\u306a\u30c7\u30fc\u30bf\u7ba1\u7406<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306e\u30c7\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u6a5f\u80fd\u306f\u3001UI\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3068\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u306e\u30c7\u30fc\u30bf\u30e2\u30c7\u30eb\u3092 seamless \u306b\u9023\u643a\u3055\u305b\u307e\u3059\u3002\u53cc\u65b9\u5411\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306b\u3088\u308a\u3001\u30c7\u30fc\u30bf\u306e\u5909\u66f4\u3092\u81ea\u52d5\u7684\u306b\u540c\u671f\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u4f8b\u3048\u3070\u3001\u30e6\u30fc\u30b6\u30fc\u60c5\u5831\u3092\u7de8\u96c6\u3059\u308b\u30d5\u30a9\u30fc\u30e0\u3092\u4f5c\u6210\u3059\u308b\u5834\u5408\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class UserEditor extends FormLayout {\n    private final Binder&lt;User&gt; binder = new Binder&lt;&gt;(User.class);\n\n    public UserEditor() {\n        \/\/ \u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u4f5c\u6210\n        TextField firstName = new TextField(\"\u540d\");\n        TextField lastName = new TextField(\"\u59d3\");\n        EmailField email = new EmailField(\"\u30e1\u30fc\u30eb\");\n\n        \/\/ \u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306e\u8a2d\u5b9a\n        binder.forField(firstName)\n            .asRequired(\"\u540d\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\")\n            .bind(User::getFirstName, User::setFirstName);\n\n        binder.forField(lastName)\n            .asRequired(\"\u59d3\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\")\n            .bind(User::getLastName, User::setLastName);\n\n        binder.forField(email)\n            .asRequired(\"\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\")\n            .withValidator(\n                email -&gt; email.contains(\"@\"),\n                \"\u6709\u52b9\u306a\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\"\n            )\n            .bind(User::getEmail, User::setEmail);\n\n        \/\/ \u30ec\u30a4\u30a2\u30a6\u30c8\u306b\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u8ffd\u52a0\n        add(firstName, lastName, email);\n    }\n\n    public void setUser(User user) {\n        binder.setBean(user);\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-7\">\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u30c7\u30b6\u30a4\u30f3\u306e\u81ea\u52d5\u30b5\u30dd\u30fc\u30c8<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306f\u3001\u30e2\u30c0\u30f3\u306a\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6Web\u30c7\u30b6\u30a4\u30f3\u3092\u6a19\u6e96\u3067\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002Flexbox\u3084CSS Grid\u30d9\u30fc\u30b9\u306e\u30ec\u30a4\u30a2\u30a6\u30c8\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u69d8\u3005\u306a\u753b\u9762\u30b5\u30a4\u30ba\u306b\u9069\u5fdc\u3059\u308bUI\u3092\u7c21\u5358\u306b\u4f5c\u6210\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u306a\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\u306e\u4f8b\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"dashboard\")\npublic class DashboardView extends Div {\n    public DashboardView() {\n        \/\/ CSS Grid\u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u8a2d\u5b9a\n        addClassName(\"dashboard-layout\");\n        getStyle().set(\"display\", \"grid\")\n            .set(\"grid-template-columns\", \"repeat(auto-fit, minmax(300px, 1fr))\")\n            .set(\"gap\", \"1rem\")\n            .set(\"padding\", \"1rem\");\n\n        \/\/ \u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\u30a2\u30a4\u30c6\u30e0\u306e\u4f5c\u6210\n        Card salesCard = createMetricCard(\n            \"\u58f2\u4e0a\", \n            \"\u00a51,234,567\", \n            \"\u524d\u6708\u6bd4 +12%\"\n        );\n        Card usersCard = createMetricCard(\n            \"\u30e6\u30fc\u30b6\u30fc\u6570\", \n            \"45,678\", \n            \"\u524d\u65e5\u6bd4 +156\"\n        );\n        Card ordersCard = createMetricCard(\n            \"\u6ce8\u6587\u6570\", \n            \"892\", \n            \"\u6642\u9593\u5225 +23\"\n        );\n\n        \/\/ \u30ab\u30fc\u30c9\u306e\u8ffd\u52a0\n        add(salesCard, usersCard, ordersCard);\n    }\n\n    private Card createMetricCard(String title, String value, String change) {\n        Card card = new Card();\n        card.addClassName(\"metric-card\");\n\n        \/\/ \u30ab\u30fc\u30c9\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u4f5c\u6210\n        H3 titleH3 = new H3(title);\n        H2 valueH2 = new H2(value);\n        Span changeSpan = new Span(change);\n\n        \/\/ \u30b9\u30bf\u30a4\u30ea\u30f3\u30b0\n        card.getStyle()\n            .set(\"padding\", \"1rem\")\n            .set(\"background\", \"var(--lumo-base-color)\")\n            .set(\"border-radius\", \"var(--lumo-border-radius)\");\n\n        card.add(titleH3, valueH2, changeSpan);\n        return card;\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u306e\u30b3\u30fc\u30c9\u306f\u3001\u753b\u9762\u30b5\u30a4\u30ba\u306b\u5fdc\u3058\u3066\u81ea\u52d5\u7684\u306b\u30ab\u30fc\u30c9\u306e\u914d\u7f6e\u3092\u8abf\u6574\u3059\u308b\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002CSS Grid\u306e<code>auto-fit<\/code>\u3068<code>minmax<\/code>\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u306a\u632f\u308b\u821e\u3044\u3092\u5b9f\u73fe\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u3055\u3089\u306b\u3001Vaadin\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u9ad8\u5ea6\u306a\u6a5f\u80fd\u3082\u63d0\u4f9b\u3057\u3066\u3044\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d6\u30ec\u30a4\u30af\u30dd\u30a4\u30f3\u30c8\u306b\u57fa\u3065\u304f\u6761\u4ef6\u4ed8\u304d\u30ec\u30f3\u30c0\u30ea\u30f3\u30b0<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Breakpoint\u306b\u3088\u308b\u8981\u7d20\u306e\u8868\u793a\/\u975e\u8868\u793a\u306e\u5236\u5fa1<\/li>\n\n\n\n<li>\u30c7\u30d0\u30a4\u30b9\u30bf\u30a4\u30d7\u306b\u5fdc\u3058\u305f\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u5207\u308a\u66ff\u3048<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30bf\u30c3\u30c1\u30c7\u30d0\u30a4\u30b9\u306e\u30b5\u30dd\u30fc\u30c8<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30bf\u30c3\u30c1\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u306e\u8a8d\u8b58<\/li>\n\n\n\n<li>\u30e2\u30d0\u30a4\u30eb\u30d5\u30ec\u30f3\u30c9\u30ea\u30fc\u306a\u30a4\u30f3\u30bf\u30e9\u30af\u30b7\u30e7\u30f3<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c6\u30fc\u30de\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CSS\u30ab\u30b9\u30bf\u30e0\u30d7\u30ed\u30d1\u30c6\u30a3\u306b\u3088\u308b\u30c6\u30fc\u30de\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30c0\u30fc\u30af\u30e2\u30fc\u30c9\/\u30e9\u30a4\u30c8\u30e2\u30fc\u30c9\u306e\u5207\u308a\u66ff\u3048<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u6a5f\u80fd\u306b\u3088\u308a\u3001\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u304b\u3089\u30e2\u30d0\u30a4\u30eb\u307e\u3067\u3001\u4e00\u8cab\u3057\u305f\u4f7f\u3044\u3084\u3059\u3044UI\u3092\u63d0\u4f9b\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-8\">Vaadin\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u59cb\u3081\u65b9\uff1a\u74b0\u5883\u69cb\u7bc9\u304b\u3089Hello World\u307e\u3067<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-9\">\u958b\u767a\u74b0\u5883\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u624b\u9806<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u958b\u767a\u3092\u59cb\u3081\u308b\u305f\u3081\u306e\u74b0\u5883\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3092\u9806\u3092\u8ffd\u3063\u3066\u8aac\u660e\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u524d\u63d0\u6761\u4ef6\u306e\u78ba\u8a8d<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JDK 17\u4ee5\u4e0a<\/li>\n\n\n\n<li>Maven 3.5\u4ee5\u4e0a \u307e\u305f\u306f Gradle 7.0\u4ee5\u4e0a<\/li>\n\n\n\n<li>IDE\uff08\u63a8\u5968\uff1aIntelliJ IDEA \u307e\u305f\u306f Eclipse\uff09<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>IDE\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # IntelliJ IDEA\u306e\u5834\u5408\n   # Vaadin plugin\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\n   # Settings &gt; Plugins &gt; Marketplace \u304b\u3089 \"Vaadin\" \u3092\u691c\u7d22\u3057\u3066\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\n\n   # Eclipse\u306e\u5834\u5408\n   # Help &gt; Eclipse Marketplace \u304b\u3089 \"Vaadin\" \u3092\u691c\u7d22\u3057\u3066\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u5fc5\u8981\u306a\u30c4\u30fc\u30eb\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # Node.js\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\uff08\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u30d3\u30eb\u30c9\u7528\uff09\n   # https:\/\/nodejs.org\/\u304b\u3089LTS\u7248\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\n\n   # Maven\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\uff08\u672a\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u306e\u5834\u5408\uff09\n   # macOS (Homebrew)\n   brew install maven\n\n   # Windows (Chocolatey)\n   choco install maven<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-10\">\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u9078\u629e\u3068\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306f\u8907\u6570\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u63d0\u4f9b\u3057\u3066\u304a\u308a\u3001\u7528\u9014\u306b\u5fdc\u3058\u3066\u9078\u629e\u3067\u304d\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30b9\u30bf\u30fc\u30bf\u30fc\u306e\u7a2e\u985e<\/strong> \u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u540d \u7279\u5fb4 \u7528\u9014 Basic \u6700\u5c0f\u9650\u306e\u69cb\u6210 \u30b7\u30f3\u30d7\u30eb\u306a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3 Full Stack Spring Boot\u7d71\u5408\u6e08\u307f \u672c\u683c\u7684\u306aWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3 Business App \u8a8d\u8a3c\u30fb\u8a8d\u53ef\u542b\u3080 \u696d\u52d9\u30b7\u30b9\u30c6\u30e0<\/li>\n\n\n\n<li><strong>\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u4f5c\u6210\u30b3\u30de\u30f3\u30c9<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # Maven\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\n   mvn archetype:generate \\\n   -DarchetypeGroupId=com.vaadin \\\n   -DarchetypeArtifactId=vaadin-archetype-spring \\\n   -DarchetypeVersion=24.3.3 \\\n   -DgroupId=com.example \\\n   -DartifactId=my-vaadin-app \\\n   -Dversion=1.0-SNAPSHOT<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u69cb\u6210\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   &lt;!-- pom.xml\u306e\u4e3b\u8981\u306a\u8a2d\u5b9a\u9805\u76ee --&gt;\n   &lt;properties&gt;\n       &lt;vaadin.version&gt;24.3.3&lt;\/vaadin.version&gt;\n       &lt;java.version&gt;17&lt;\/java.version&gt;\n       &lt;spring-boot.version&gt;3.2.0&lt;\/spring-boot.version&gt;\n   &lt;\/properties&gt;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-11\">\u6700\u521d\u306eVaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u4f5c\u6210<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Hello World\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\u3057\u3066\u3001Vaadin\u306e\u57fa\u672c\u7684\u306a\u4f7f\u3044\u65b9\u3092\u7406\u89e3\u3057\u307e\u3057\u3087\u3046\u3002<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e1\u30a4\u30f3\u30d3\u30e5\u30fc\u306e\u4f5c\u6210<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   package com.example.application.views;\n\n   import com.vaadin.flow.component.button.Button;\n   import com.vaadin.flow.component.notification.Notification;\n   import com.vaadin.flow.component.orderedlayout.VerticalLayout;\n   import com.vaadin.flow.router.Route;\n   import com.vaadin.flow.router.PageTitle;\n\n   @Route(\"\")\n   @PageTitle(\"Hello World\")\n   public class MainView extends VerticalLayout {\n       public MainView() {\n           \/\/ \u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u8a2d\u5b9a\n           setDefaultHorizontalComponentAlignment(Alignment.CENTER);\n           setJustifyContentMode(JustifyContentMode.CENTER);\n           setHeight(\"100vh\");\n\n           \/\/ \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u4f5c\u6210\n           Button button = new Button(\"Click me!\");\n           button.addClickListener(event -&gt; {\n               Notification.show(\"Hello World!\");\n           });\n\n           \/\/ \u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u8ffd\u52a0\n           add(button);\n       }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u8d77\u52d5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   package com.example.application;\n\n   import org.springframework.boot.SpringApplication;\n   import org.springframework.boot.autoconfigure.SpringBootApplication;\n\n   @SpringBootApplication\n   public class Application {\n       public static void main(String[] args) {\n           SpringApplication.run(Application.class, args);\n       }\n   }<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u884c<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # Maven\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\n   mvn spring-boot:run\n\n   # Gradle\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\n   .\/gradlew bootRun<\/pre>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>\u958b\u767a\u30e2\u30fc\u30c9\u306e\u6d3b\u7528<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # \u958b\u767a\u30e2\u30fc\u30c9\u3067\u306e\u8d77\u52d5\uff08\u30db\u30c3\u30c8\u30ea\u30ed\u30fc\u30c9\u6709\u52b9\uff09\n   mvn vaadin:prepare-frontend vaadin:build vaadin:dev-server<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u8d77\u52d5\u5f8c\u3001\u4ee5\u4e0b\u306eURL\u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u958b\u767a\u30e2\u30fc\u30c9: http:\/\/localhost:8080<\/li>\n\n\n\n<li>\u672c\u756a\u30e2\u30fc\u30c9: http:\/\/localhost:8080<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u958b\u767a\u4e2d\u306e\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u3088\u304f\u3042\u308b\u554f\u984c\u3068\u89e3\u6c7a\u7b56<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>node_modules<\/code>\u95a2\u9023\u306e\u30a8\u30e9\u30fc \u2192 <code>mvn clean install<\/code>\u3092\u5b9f\u884c<\/li>\n\n\n\n<li>\u30db\u30c3\u30c8\u30ea\u30ed\u30fc\u30c9\u304c\u52b9\u304b\u306a\u3044 \u2192 <code>application.properties<\/code>\u3067<code>spring.devtools.restart.enabled=true<\/code>\u3092\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30b3\u30f3\u30d1\u30a4\u30eb\u30a8\u30e9\u30fc \u2192 JDK\u30d0\u30fc\u30b8\u30e7\u30f3\u3068\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u8a2d\u5b9a\u306e\u6574\u5408\u6027\u3092\u78ba\u8a8d<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c7\u30d0\u30c3\u30b0\u306e\u30dd\u30a4\u30f3\u30c8<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30d6\u30e9\u30a6\u30b6\u306e\u958b\u767a\u8005\u30c4\u30fc\u30eb\u3067\u30b3\u30f3\u30bd\u30fc\u30eb\u30ed\u30b0\u3092\u78ba\u8a8d<\/li>\n\n\n\n<li>\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u306e\u30ed\u30b0\u306f<code>application.properties<\/code>\u3067<code>logging.level.com.vaadin=DEBUG<\/code>\u3092\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u30d3\u30eb\u30c9\u306e\u8a73\u7d30\u30ed\u30b0\u306f<code>mvn vaadin:build -X<\/code>\u3067\u78ba\u8a8d<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u624b\u9806\u306b\u5f93\u3048\u3070\u3001\u57fa\u672c\u7684\u306aVaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u958b\u767a\u74b0\u5883\u304c\u6574\u3044\u307e\u3059\u3002\u6b21\u306e\u30b9\u30c6\u30c3\u30d7\u3067\u306f\u3001\u3053\u306e\u57fa\u672c\u74b0\u5883\u3092\u571f\u53f0\u306b\u3088\u308a\u9ad8\u5ea6\u306a\u6a5f\u80fd\u3092\u5b9f\u88c5\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-12\">\u5b9f\u8df5\u7684\u306aVaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u30ac\u30a4\u30c9<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-13\">\u30d5\u30a9\u30fc\u30e0\u4f5c\u6210\u3068\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u5b9f\u88c5\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u30d5\u30a9\u30fc\u30e0\u5b9f\u88c5\u306f\u696d\u52d9\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u8981\u3068\u306a\u308b\u90e8\u5206\u3067\u3059\u3002Vaadin\u3067\u306f\u3001Binder\u30af\u30e9\u30b9\u3092\u6d3b\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u5805\u7262\u306a\u30d5\u30a9\u30fc\u30e0\u5b9f\u88c5\u3092\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"user-registration\")\npublic class UserRegistrationForm extends FormLayout {\n    private final UserService userService;\n    private final Binder&lt;UserDTO&gt; binder;\n\n    \/\/ \u30d5\u30a9\u30fc\u30e0\u30d5\u30a3\u30fc\u30eb\u30c9\n    private final TextField username = new TextField(\"\u30e6\u30fc\u30b6\u30fc\u540d\");\n    private final PasswordField password = new PasswordField(\"\u30d1\u30b9\u30ef\u30fc\u30c9\");\n    private final EmailField email = new EmailField(\"\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\");\n    private final DatePicker birthDate = new DatePicker(\"\u751f\u5e74\u6708\u65e5\");\n    private final Button submit = new Button(\"\u767b\u9332\");\n    private final Button reset = new Button(\"\u30ea\u30bb\u30c3\u30c8\");\n\n    public UserRegistrationForm(UserService userService) {\n        this.userService = userService;\n        this.binder = new Binder&lt;&gt;(UserDTO.class);\n\n        \/\/ \u30ec\u30a4\u30a2\u30a6\u30c8\u8a2d\u5b9a\n        setMaxWidth(\"600px\");\n        setResponsiveSteps(\n            new ResponsiveStep(\"0\", 1),\n            new ResponsiveStep(\"500px\", 2)\n        );\n\n        \/\/ \u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u306e\u8a2d\u5b9a\n        binder.forField(username)\n            .asRequired(\"\u30e6\u30fc\u30b6\u30fc\u540d\u306f\u5fc5\u9808\u3067\u3059\")\n            .withValidator(\n                name -&gt; name.length() &gt;= 3,\n                \"\u30e6\u30fc\u30b6\u30fc\u540d\u306f3\u6587\u5b57\u4ee5\u4e0a\u5fc5\u8981\u3067\u3059\"\n            )\n            .bind(UserDTO::getUsername, UserDTO::setUsername);\n\n        binder.forField(password)\n            .asRequired(\"\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u5fc5\u9808\u3067\u3059\")\n            .withValidator(\n                this::validatePassword,\n                \"\u30d1\u30b9\u30ef\u30fc\u30c9\u306f8\u6587\u5b57\u4ee5\u4e0a\u3067\u3001\u82f1\u6570\u5b57\u3092\u542b\u3080\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\"\n            )\n            .bind(UserDTO::getPassword, UserDTO::setPassword);\n\n        \/\/ \u30dc\u30bf\u30f3\u30a4\u30d9\u30f3\u30c8\u306e\u8a2d\u5b9a\n        submit.addClickListener(e -&gt; {\n            try {\n                UserDTO dto = new UserDTO();\n                if (binder.writeBeanIfValid(dto)) {\n                    userService.registerUser(dto);\n                    Notification.show(\"\u767b\u9332\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f\");\n                    clearForm();\n                }\n            } catch (Exception ex) {\n                Notification.show(\"\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f: \" + ex.getMessage());\n            }\n        });\n\n        reset.addClickListener(e -&gt; clearForm());\n\n        \/\/ \u30d5\u30a9\u30fc\u30e0\u306e\u69cb\u7bc9\n        add(username, password, email, birthDate, \n            new HorizontalLayout(submit, reset));\n    }\n\n    private boolean validatePassword(String password) {\n        return password.length() &gt;= 8 &amp;&amp;\n               password.matches(\".*[A-Za-z].*\") &amp;&amp;\n               password.matches(\".*[0-9].*\");\n    }\n\n    private void clearForm() {\n        binder.readBean(new UserDTO());\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-14\">\u30b0\u30ea\u30c3\u30c9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u4f7f\u7528\u3057\u305f\u30c7\u30fc\u30bf\u8868\u793a\u3068\u64cd\u4f5c<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306e\u30b0\u30ea\u30c3\u30c9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306f\u3001\u5927\u91cf\u306e\u30c7\u30fc\u30bf\u3092\u52b9\u7387\u7684\u306b\u8868\u793a\u30fb\u64cd\u4f5c\u3059\u308b\u305f\u3081\u306e\u5f37\u529b\u306a\u6a5f\u80fd\u3092\u63d0\u4f9b\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"users\")\npublic class UserGridView extends VerticalLayout {\n    private final Grid&lt;User&gt; grid = new Grid&lt;&gt;(User.class, false);\n    private final UserService userService;\n\n    public UserGridView(UserService userService) {\n        this.userService = userService;\n\n        \/\/ \u30b0\u30ea\u30c3\u30c9\u306e\u8a2d\u5b9a\n        grid.addColumn(User::getId).setHeader(\"ID\")\n            .setSortable(true);\n        grid.addColumn(User::getUsername).setHeader(\"\u30e6\u30fc\u30b6\u30fc\u540d\")\n            .setFilter(true);\n        grid.addColumn(User::getEmail).setHeader(\"\u30e1\u30fc\u30eb\")\n            .setFilter(true);\n        grid.addColumn(User::getCreatedAt).setHeader(\"\u4f5c\u6210\u65e5\")\n            .setSortable(true);\n\n        \/\/ \u7de8\u96c6\u30ab\u30e9\u30e0\u306e\u8ffd\u52a0\n        grid.addComponentColumn(user -&gt; {\n            HorizontalLayout actions = new HorizontalLayout();\n            Button editButton = new Button(\"\u7de8\u96c6\", e -&gt; editUser(user));\n            Button deleteButton = new Button(\"\u524a\u9664\", e -&gt; deleteUser(user));\n            actions.add(editButton, deleteButton);\n            return actions;\n        });\n\n        \/\/ \u30c7\u30fc\u30bf\u30d7\u30ed\u30d0\u30a4\u30c0\u30fc\u306e\u8a2d\u5b9a\n        grid.setItems(query -&gt; userService.list(\n            PageRequest.of(query.getPage(), query.getPageSize(), \n                          getSort(query)))\n            .stream());\n\n        \/\/ \u30b0\u30ea\u30c3\u30c9\u306e\u8a73\u7d30\u8a2d\u5b9a\n        grid.setSelectionMode(Grid.SelectionMode.MULTI);\n        grid.setHeight(\"500px\");\n\n        \/\/ \u30c4\u30fc\u30eb\u30d0\u30fc\u306e\u8ffd\u52a0\n        Button addButton = new Button(\"\u65b0\u898f\u8ffd\u52a0\", e -&gt; showUserDialog(null));\n        Button refreshButton = new Button(\"\u66f4\u65b0\", e -&gt; grid.getDataProvider().refreshAll());\n\n        add(new HorizontalLayout(addButton, refreshButton), grid);\n    }\n\n    private Sort getSort(Query&lt;User, Void&gt; query) {\n        \/\/ \u30bd\u30fc\u30c8\u6761\u4ef6\u306e\u69cb\u7bc9\n        List&lt;Sort.Order&gt; orders = query.getSortOrders().stream()\n            .map(querySortOrder -&gt; {\n                Sort.Direction direction = querySortOrder.getDirection() == SortDirection.ASCENDING ? \n                    Sort.Direction.ASC : Sort.Direction.DESC;\n                return new Sort.Order(direction, querySortOrder.getSorted());\n            })\n            .collect(Collectors.toList());\n        return orders.isEmpty() ? Sort.unsorted() : Sort.by(orders);\n    }\n\n    private void editUser(User user) {\n        \/\/ \u7de8\u96c6\u30c0\u30a4\u30a2\u30ed\u30b0\u306e\u8868\u793a\n        UserDialog dialog = new UserDialog(user, userService);\n        dialog.addOpenedChangeListener(e -&gt; {\n            if (!e.isOpened()) {\n                grid.getDataProvider().refreshAll();\n            }\n        });\n        dialog.open();\n    }\n\n    private void deleteUser(User user) {\n        \/\/ \u524a\u9664\u78ba\u8a8d\u30c0\u30a4\u30a2\u30ed\u30b0\n        ConfirmDialog dialog = new ConfirmDialog();\n        dialog.setHeader(\"\u30e6\u30fc\u30b6\u30fc\u306e\u524a\u9664\");\n        dialog.setText(\"\u672c\u5f53\u306b\u524a\u9664\u3057\u307e\u3059\u304b\uff1f\");\n\n        dialog.setCancelable(true);\n        dialog.setConfirmText(\"\u524a\u9664\");\n        dialog.setCancelText(\"\u30ad\u30e3\u30f3\u30bb\u30eb\");\n\n        dialog.addConfirmListener(event -&gt; {\n            userService.deleteUser(user.getId());\n            grid.getDataProvider().refreshAll();\n            Notification.show(\"\u30e6\u30fc\u30b6\u30fc\u3092\u524a\u9664\u3057\u307e\u3057\u305f\");\n        });\n\n        dialog.open();\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-15\">\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\u3068\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u306e\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\u30b7\u30b9\u30c6\u30e0\u3092\u4f7f\u7528\u3057\u3066\u3001\u30b7\u30f3\u30b0\u30eb\u30da\u30fc\u30b8\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\uff08SPA\uff09\u306e\u3088\u3046\u306a\u6ed1\u3089\u304b\u306a\u9077\u79fb\u3092\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"\")\n@PageTitle(\"\u30e1\u30a4\u30f3\u30ec\u30a4\u30a2\u30a6\u30c8\")\npublic class MainLayout extends AppLayout {\n\n    public MainLayout() {\n        \/\/ \u30d8\u30c3\u30c0\u30fc\u306e\u4f5c\u6210\n        H1 title = new H1(\"\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u540d\");\n        title.getStyle().set(\"font-size\", \"var(--lumo-font-size-l)\")\n            .set(\"margin\", \"0\");\n\n        \/\/ \u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\u30e1\u30cb\u30e5\u30fc\u306e\u4f5c\u6210\n        DrawerToggle toggle = new DrawerToggle();\n\n        \/\/ \u30bf\u30d6\u306e\u4f5c\u6210\n        Tabs tabs = createNavigationTabs();\n\n        addToNavbar(toggle, title);\n        addToDrawer(createNavigationLinks());\n    }\n\n    private Tabs createNavigationTabs() {\n        Tabs tabs = new Tabs();\n        tabs.add(\n            createTab(\"\u30db\u30fc\u30e0\", HomeView.class),\n            createTab(\"\u30e6\u30fc\u30b6\u30fc\", UserGridView.class),\n            createTab(\"\u8a2d\u5b9a\", SettingsView.class)\n        );\n        tabs.setOrientation(Tabs.Orientation.HORIZONTAL);\n        return tabs;\n    }\n\n    private Tab createTab(String text, Class&lt;? extends Component&gt; navigationTarget) {\n        Tab tab = new Tab();\n        RouterLink link = new RouterLink();\n        link.setRoute(navigationTarget);\n        link.add(new Span(text));\n        tab.add(link);\n        return tab;\n    }\n\n    private VerticalLayout createNavigationLinks() {\n        VerticalLayout layout = new VerticalLayout();\n        layout.add(\n            createRouterLink(\"\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\", DashboardView.class),\n            createRouterLink(\"\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\", ProfileView.class),\n            createRouterLink(\"\u30ed\u30b0\u30a2\u30a6\u30c8\", LogoutView.class)\n        );\n        return layout;\n    }\n\n    private RouterLink createRouterLink(String text, Class&lt;? extends Component&gt; view) {\n        RouterLink link = new RouterLink(text, view);\n        link.getStyle().set(\"margin\", \"0.5em\");\n        return link;\n    }\n}\n\n@Route(value = \"dashboard\", layout = MainLayout.class)\n@PageTitle(\"\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\")\npublic class DashboardView extends VerticalLayout {\n    \/\/ \u30d3\u30e5\u30fc\u306e\u5b9f\u88c5\n}\n\n@Route(value = \"profile\", layout = MainLayout.class)\n@PageTitle(\"\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\")\npublic class ProfileView extends VerticalLayout {\n    \/\/ \u30d3\u30e5\u30fc\u306e\u5b9f\u88c5\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u306e\u30b3\u30fc\u30c9\u30d9\u30fc\u30b9\u306f\u3001\u4ee5\u4e0b\u306e\u4e3b\u8981\u306a\u6a5f\u80fd\u3092\u63d0\u4f9b\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u306a\u30ca\u30d3\u30b2\u30fc\u30b7\u30e7\u30f3\u30e1\u30cb\u30e5\u30fc<\/li>\n\n\n\n<li>URL\u30d9\u30fc\u30b9\u306e\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0<\/li>\n\n\n\n<li>\u30d3\u30e5\u30fc\u306e\u9077\u79fb\u7ba1\u7406<\/li>\n\n\n\n<li>\u30d1\u30f3\u304f\u305a\u30ea\u30b9\u30c8\u306e\u30b5\u30dd\u30fc\u30c8<\/li>\n\n\n\n<li>\u30da\u30fc\u30b8\u30bf\u30a4\u30c8\u30eb\u306e\u52d5\u7684\u66f4\u65b0<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u5b9f\u88c5\u4f8b\u3092\u57fa\u306b\u3001\u5b9f\u969b\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306b\u5fdc\u3058\u3066\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3059\u308b\u3053\u3068\u3067\u3001\u4f7f\u3044\u3084\u3059\u304f\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u69cb\u7bc9\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-16\">Vaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u672c\u756a\u74b0\u5883\u3078\u306e\u5c55\u958b<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-17\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30c6\u30af\u30cb\u30c3\u30af<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u672c\u756a\u74b0\u5883\u3067\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u6700\u5927\u5316\u3059\u308b\u305f\u3081\u306b\u3001\u4ee5\u4e0b\u306e\u6700\u9069\u5316\u30c6\u30af\u30cb\u30c3\u30af\u3092\u9069\u7528\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d7\u30ed\u30c0\u30af\u30b7\u30e7\u30f3\u30e2\u30fc\u30c9\u306e\u6709\u52b9\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># application.properties\nvaadin.productionMode=true<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u9759\u7684\u30ea\u30bd\u30fc\u30b9\u306e\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- pom.xml --&gt;\n&lt;plugin&gt;\n    &lt;groupId&gt;com.vaadin&lt;\/groupId&gt;\n    &lt;artifactId&gt;vaadin-maven-plugin&lt;\/artifactId&gt;\n    &lt;version&gt;${vaadin.version}&lt;\/version&gt;\n    &lt;executions&gt;\n        &lt;execution&gt;\n            &lt;goals&gt;\n                &lt;goal&gt;prepare-frontend&lt;\/goal&gt;\n                &lt;goal&gt;build-frontend&lt;\/goal&gt;\n            &lt;\/goals&gt;\n            &lt;configuration&gt;\n                &lt;productionMode&gt;true&lt;\/productionMode&gt;\n                &lt;optimizeBundle&gt;true&lt;\/optimizeBundle&gt;\n            &lt;\/configuration&gt;\n        &lt;\/execution&gt;\n    &lt;\/executions&gt;\n&lt;\/plugin&gt;<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30ec\u30a4\u30b8\u30fc\u30ed\u30fc\u30c7\u30a3\u30f3\u30b0\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"lazy-view\")\n@RouteAlias(\"\")\n@PageTitle(\"LazyView\")\npublic class LazyView extends VerticalLayout {\n\n    public LazyView() {\n        \/\/ \u9045\u5ef6\u30ed\u30fc\u30c9\u3059\u308b\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\n        Button loadDataButton = new Button(\"\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3080\");\n        Div contentContainer = new Div();\n\n        loadDataButton.addClickListener(e -&gt; {\n            \/\/ \u975e\u540c\u671f\u3067\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3080\n            UI.getCurrent().access(() -&gt; {\n                contentContainer.add(new LazyLoadedComponent());\n            });\n        });\n\n        add(loadDataButton, contentContainer);\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-18\">\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306f\u672c\u756a\u74b0\u5883\u3067\u6700\u3082\u91cd\u8981\u306a\u8981\u7d20\u306e\u4e00\u3064\u3067\u3059\u3002Vaadin\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3067\u306f\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Spring Security\u3068\u306e\u7d71\u5408<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Configuration\n@EnableWebSecurity\npublic class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        super.configure(http);\n        setLoginView(http, LoginView.class);\n\n        http.authorizeRequests()\n            .antMatchers(\"\/public\/**\").permitAll()\n            .antMatchers(\"\/api\/**\").authenticated()\n            .antMatchers(\"\/admin\/**\").hasRole(\"ADMIN\")\n            .anyRequest().authenticated();\n\n        http.csrf().ignoringAntMatchers(\"\/api\/**\");\n    }\n\n    @Override\n    public void configure(WebSecurity web) throws Exception {\n        super.configure(web);\n        web.ignoring().antMatchers(\n            \"\/images\/**\",\n            \"\/icons\/**\",\n            \"\/robots.txt\"\n        );\n    }\n}<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>CSRF\u30c8\u30fc\u30af\u30f3\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"secure-form\")\npublic class SecureForm extends VerticalLayout {\n    private final CsrfToken csrf;\n\n    public SecureForm(@CsrfToken CsrfToken csrf) {\n        this.csrf = csrf;\n\n        \/\/ CSRF\u30c8\u30fc\u30af\u30f3\u3092\u30d5\u30a9\u30fc\u30e0\u306b\u8ffd\u52a0\n        TextField csrfField = new TextField();\n        csrfField.setVisible(false);\n        csrfField.setValue(csrf.getToken());\n\n        add(csrfField);\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-19\">\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u30d7\u30ed\u30bb\u30b9\u3068\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u672c\u756a\u74b0\u5883\u3078\u306e\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u306f\u3001\u4ee5\u4e0b\u306e\u624b\u9806\u3068\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u306b\u5f93\u3063\u3066\u5b9f\u65bd\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d3\u30eb\u30c9\u30d7\u30ed\u30bb\u30b9\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- pom.xml --&gt;\n&lt;profiles&gt;\n    &lt;profile&gt;\n        &lt;id&gt;production&lt;\/id&gt;\n        &lt;properties&gt;\n            &lt;vaadin.productionMode&gt;true&lt;\/vaadin.productionMode&gt;\n        &lt;\/properties&gt;\n        &lt;dependencies&gt;\n            &lt;dependency&gt;\n                &lt;groupId&gt;com.vaadin&lt;\/groupId&gt;\n                &lt;artifactId&gt;flow-server-production-mode&lt;\/artifactId&gt;\n            &lt;\/dependency&gt;\n        &lt;\/dependencies&gt;\n        &lt;build&gt;\n            &lt;plugins&gt;\n                &lt;plugin&gt;\n                    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n                    &lt;artifactId&gt;spring-boot-maven-plugin&lt;\/artifactId&gt;\n                    &lt;configuration&gt;\n                        &lt;layers&gt;\n                            &lt;enabled&gt;true&lt;\/enabled&gt;\n                        &lt;\/layers&gt;\n                    &lt;\/configuration&gt;\n                &lt;\/plugin&gt;\n            &lt;\/plugins&gt;\n        &lt;\/build&gt;\n    &lt;\/profile&gt;\n&lt;\/profiles&gt;<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Docker\u74b0\u5883\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Dockerfile\nFROM adoptopenjdk:17-jdk-hotspot as builder\nWORKDIR \/app\nCOPY . .\nRUN .\/mvnw clean package -Pproduction\n\nFROM adoptopenjdk:17-jre-hotspot\nWORKDIR \/app\nCOPY --from=builder \/app\/target\/*.jar app.jar\nEXPOSE 8080\nENTRYPOINT [\"java\", \"-jar\", \"app.jar\"]<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u74b0\u5883\u8a2d\u5b9a\u306e\u5916\u90e8\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># application.yml\nspring:\n  profiles:\n    active: ${SPRING_PROFILES_ACTIVE:prod}\n  datasource:\n    url: ${JDBC_DATABASE_URL}\n    username: ${JDBC_DATABASE_USERNAME}\n    password: ${JDBC_DATABASE_PASSWORD}\n\nvaadin:\n  productionMode: true\n  compatibilityMode: false\n  pnpm:\n    enable: true\n\nlogging:\n  level:\n    org.atmosphere: warn\n    com.vaadin: ${VAADIN_LOG_LEVEL:INFO}<\/pre>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Configuration\npublic class MonitoringConfig {\n\n    @Bean\n    public MeterRegistry meterRegistry() {\n        return new SimpleMeterRegistry();\n    }\n\n    @Bean\n    public VaadinRequestTracker vaadinRequestTracker(MeterRegistry registry) {\n        return new VaadinRequestTracker(registry);\n    }\n}\n\n@Component\npublic class VaadinRequestTracker {\n    private final Counter requestCounter;\n    private final Timer requestTimer;\n\n    public VaadinRequestTracker(MeterRegistry registry) {\n        this.requestCounter = Counter.builder(\"vaadin.requests\")\n            .description(\"Number of Vaadin requests\")\n            .register(registry);\n\n        this.requestTimer = Timer.builder(\"vaadin.request.duration\")\n            .description(\"Vaadin request duration\")\n            .register(registry);\n    }\n\n    @EventListener\n    public void onVaadinRequest(RequestHandlingEvent event) {\n        requestCounter.increment();\n        requestTimer.record(event.getDuration());\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u6642\u306e\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u672c\u756a\u74b0\u5883\u6e96\u5099<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30e1\u30e2\u30ea\u8a2d\u5b9a\u306e\u6700\u9069\u5316<\/li>\n\n\n\n<li>\u30ed\u30b0\u30ec\u30d9\u30eb\u306e\u8abf\u6574<\/li>\n\n\n\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8a2d\u5b9a\u306e\u78ba\u8a8d<\/li>\n\n\n\n<li>\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u6226\u7565\u306e\u78ba\u8a8d<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u624b\u9806<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u884c<\/li>\n\n\n\n<li>\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30d3\u30eb\u30c9\u3068\u691c\u8a3c<\/li>\n\n\n\n<li>Blue-Green\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u306e\u5b9f\u65bd<\/li>\n\n\n\n<li>\u30d8\u30eb\u30b9\u30c1\u30a7\u30c3\u30af\u306e\u78ba\u8a8d<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u3068\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u30e1\u30c8\u30ea\u30af\u30b9\u306e\u76e3\u8996<\/li>\n\n\n\n<li>\u30a8\u30e9\u30fc\u30ed\u30b0\u306e\u76e3\u8996<\/li>\n\n\n\n<li>\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u5b9a\u671f\u5b9f\u884c<\/li>\n\n\n\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u306e\u9069\u7528<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u8a2d\u5b9a\u3068\u624b\u9806\u3092\u9069\u5207\u306b\u5b9f\u88c5\u3059\u308b\u3053\u3068\u3067\u3001\u5b89\u5b9a\u3057\u305f\u672c\u756a\u74b0\u5883\u306e\u904b\u7528\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-20\">Vaadin\u3092\u4f7f\u7528\u3057\u305f\u958b\u767a\u306e\u5b9f\u4f8b\u3068\u30b1\u30fc\u30b9\u30b9\u30bf\u30c7\u30a3<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-21\">\u4f01\u696d\u306e\u696d\u52d9\u30b7\u30b9\u30c6\u30e0\u3078\u306e\u5c0e\u5165\u4e8b\u4f8b<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u4f01\u696d\u306e\u696d\u52d9\u30b7\u30b9\u30c6\u30e0\u3067Vaadin\u3092\u6d3b\u7528\u3057\u305f\u4e8b\u4f8b\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002\u4ee5\u4e0b\u306f\u5728\u5eab\u7ba1\u7406\u30b7\u30b9\u30c6\u30e0\u306e\u5b9f\u88c5\u4f8b\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"inventory\")\n@PageTitle(\"\u5728\u5eab\u7ba1\u7406\u30b7\u30b9\u30c6\u30e0\")\npublic class InventoryManagementView extends VerticalLayout {\n    private final Grid&lt;Product&gt; productGrid;\n    private final ProductService productService;\n    private final StockService stockService;\n\n    public InventoryManagementView(\n            ProductService productService,\n            StockService stockService) {\n        this.productService = productService;\n        this.stockService = stockService;\n\n        \/\/ \u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\u8981\u7d20\u306e\u4f5c\u6210\n        Component stockSummary = createStockSummary();\n        Component alertPanel = createAlertPanel();\n\n        \/\/ \u30b0\u30ea\u30c3\u30c9\u306e\u521d\u671f\u5316\n        this.productGrid = new Grid&lt;&gt;(Product.class);\n        setupProductGrid();\n\n        \/\/ \u30ec\u30a4\u30a2\u30a6\u30c8\u306e\u69cb\u6210\n        add(\n            new H2(\"\u5728\u5eab\u7ba1\u7406\u30b7\u30b9\u30c6\u30e0\"),\n            new HorizontalLayout(stockSummary, alertPanel),\n            createToolbar(),\n            productGrid\n        );\n    }\n\n    private Component createStockSummary() {\n        \/\/ \u5728\u5eab\u30b5\u30de\u30ea\u30fc\u30d1\u30cd\u30eb\u306e\u4f5c\u6210\n        Board board = new Board();\n        board.addRow(\n            createMetricBox(\"\u7dcf\u5728\u5eab\u6570\", stockService.getTotalStock()),\n            createMetricBox(\"\u8981\u767a\u6ce8\u5546\u54c1\", stockService.getLowStockCount()),\n            createMetricBox(\"\u904e\u5270\u5728\u5eab\", stockService.getExcessStockCount())\n        );\n        return board;\n    }\n\n    private Component createAlertPanel() {\n        \/\/ \u30a2\u30e9\u30fc\u30c8\u30d1\u30cd\u30eb\u306e\u5b9f\u88c5\n        VerticalLayout alerts = new VerticalLayout();\n        alerts.add(new H3(\"\u30a2\u30e9\u30fc\u30c8\"));\n\n        stockService.getStockAlerts().forEach(alert -&gt; {\n            Notification notification = new Notification();\n            notification.setDuration(0);\n            notification.setText(alert.getMessage());\n            alerts.add(notification);\n        });\n\n        return alerts;\n    }\n\n    private void setupProductGrid() {\n        productGrid.setColumns(\"code\", \"name\", \"category\", \"stock\", \"minimumStock\");\n        productGrid.addColumn(product -&gt; \n            stockService.getStockStatus(product).getDisplayName()\n        ).setHeader(\"\u5728\u5eab\u72b6\u614b\");\n\n        productGrid.addColumn(new ComponentRenderer&lt;&gt;(product -&gt; {\n            MenuBar actions = new MenuBar();\n            actions.addItem(\"\u5728\u5eab\u8abf\u6574\", e -&gt; adjustStock(product));\n            actions.addItem(\"\u767a\u6ce8\", e -&gt; createOrder(product));\n            return actions;\n        })).setHeader(\"\u30a2\u30af\u30b7\u30e7\u30f3\");\n\n        productGrid.setItems(productService.findAll());\n    }\n\n    private void adjustStock(Product product) {\n        \/\/ \u5728\u5eab\u8abf\u6574\u30c0\u30a4\u30a2\u30ed\u30b0\n        Dialog dialog = new Dialog();\n        dialog.setHeaderTitle(\"\u5728\u5eab\u8abf\u6574\");\n\n        NumberField quantity = new NumberField(\"\u6570\u91cf\");\n        quantity.setValue(0.0);\n\n        Button confirm = new Button(\"\u78ba\u5b9a\", e -&gt; {\n            stockService.adjustStock(product, quantity.getValue());\n            productGrid.getDataProvider().refreshItem(product);\n            dialog.close();\n        });\n\n        dialog.add(new VerticalLayout(quantity, confirm));\n        dialog.open();\n    }\n\n    private void createOrder(Product product) {\n        \/\/ \u767a\u6ce8\u51e6\u7406\u306e\u5b9f\u88c5\n        OrderForm orderForm = new OrderForm(product);\n        orderForm.addConfirmListener(e -&gt; {\n            stockService.createOrder(e.getOrder());\n            productGrid.getDataProvider().refreshItem(product);\n        });\n        orderForm.open();\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-22\">EC\u30b5\u30a4\u30c8\u958b\u767a\u3067\u306eVaadin\u306e\u6d3b\u7528\u65b9\u6cd5<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u3092\u4f7f\u7528\u3057\u305fEC\u30b5\u30a4\u30c8\u306e\u5b9f\u88c5\u4f8b\u3092\u793a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"product-catalog\")\npublic class ProductCatalogView extends VerticalLayout {\n    private final ProductCatalogService catalogService;\n    private final ShoppingCartService cartService;\n\n    public ProductCatalogView(\n            ProductCatalogService catalogService,\n            ShoppingCartService cartService) {\n        this.catalogService = catalogService;\n        this.cartService = cartService;\n\n        \/\/ \u691c\u7d22\u30d5\u30a3\u30eb\u30bf\u30fc\u306e\u4f5c\u6210\n        Component searchFilters = createSearchFilters();\n\n        \/\/ \u5546\u54c1\u30b0\u30ea\u30c3\u30c9\u306e\u4f5c\u6210\n        Component productGrid = createProductGrid();\n\n        \/\/ \u30ab\u30fc\u30c8\u30b5\u30de\u30ea\u30fc\u306e\u4f5c\u6210\n        Component cartSummary = createCartSummary();\n\n        add(\n            searchFilters,\n            new HorizontalLayout(productGrid, cartSummary)\n        );\n    }\n\n    private Component createSearchFilters() {\n        \/\/ \u691c\u7d22\u30d5\u30a3\u30eb\u30bf\u30fc\u306e\u5b9f\u88c5\n        HorizontalLayout filters = new HorizontalLayout();\n\n        \/\/ \u30ab\u30c6\u30b4\u30ea\u30d5\u30a3\u30eb\u30bf\u30fc\n        ComboBox&lt;Category&gt; categoryFilter = new ComboBox&lt;&gt;(\"\u30ab\u30c6\u30b4\u30ea\");\n        categoryFilter.setItems(catalogService.getAllCategories());\n\n        \/\/ \u4fa1\u683c\u5e2f\u30d5\u30a3\u30eb\u30bf\u30fc\n        NumberField minPrice = new NumberField(\"\u6700\u5c0f\u4fa1\u683c\");\n        NumberField maxPrice = new NumberField(\"\u6700\u5927\u4fa1\u683c\");\n\n        \/\/ \u691c\u7d22\u30dc\u30bf\u30f3\n        Button searchButton = new Button(\"\u691c\u7d22\", e -&gt; {\n            applyFilters(categoryFilter.getValue(),\n                        minPrice.getValue(),\n                        maxPrice.getValue());\n        });\n\n        filters.add(categoryFilter, minPrice, maxPrice, searchButton);\n        return filters;\n    }\n\n    private Component createProductGrid() {\n        Grid&lt;Product&gt; grid = new Grid&lt;&gt;(Product.class, false);\n\n        \/\/ \u5546\u54c1\u60c5\u5831\u30ab\u30e9\u30e0\u306e\u8a2d\u5b9a\n        grid.addColumn(new ComponentRenderer&lt;&gt;(product -&gt; {\n            Image image = new Image(\n                product.getImageUrl(),\n                product.getName()\n            );\n            image.setWidth(\"100px\");\n            return image;\n        })).setHeader(\"\u5546\u54c1\u753b\u50cf\");\n\n        grid.addColumn(Product::getName).setHeader(\"\u5546\u54c1\u540d\");\n        grid.addColumn(Product::getPrice)\n            .setHeader(\"\u4fa1\u683c\")\n            .setRenderer(new NumberRenderer&lt;&gt;(\n                Product::getPrice,\n                \"\u00a5%,d\"\n            ));\n\n        \/\/ \u30ab\u30fc\u30c8\u306b\u8ffd\u52a0\u3059\u308b\u30dc\u30bf\u30f3\n        grid.addColumn(new ComponentRenderer&lt;&gt;(product -&gt; {\n            Button addToCart = new Button(\n                \"\u30ab\u30fc\u30c8\u306b\u8ffd\u52a0\",\n                e -&gt; addProductToCart(product)\n            );\n            addToCart.addThemeVariants(\n                ButtonVariant.LUMO_PRIMARY\n            );\n            return addToCart;\n        }));\n\n        return grid;\n    }\n\n    private Component createCartSummary() {\n        \/\/ \u30ab\u30fc\u30c8\u30b5\u30de\u30ea\u30fc\u306e\u5b9f\u88c5\n        VerticalLayout cartLayout = new VerticalLayout();\n        cartLayout.setWidth(\"300px\");\n\n        H3 cartTitle = new H3(\"\u30b7\u30e7\u30c3\u30d4\u30f3\u30b0\u30ab\u30fc\u30c8\");\n\n        \/\/ \u30ab\u30fc\u30c8\u5185\u306e\u5546\u54c1\u30ea\u30b9\u30c8\n        ListBox&lt;CartItem&gt; cartItems = new ListBox&lt;&gt;();\n        cartItems.setRenderer(new ComponentRenderer&lt;&gt;(item -&gt; {\n            HorizontalLayout layout = new HorizontalLayout();\n            layout.add(\n                new Span(item.getProduct().getName()),\n                new Span(\"\u00d7 \" + item.getQuantity()),\n                new Span(\"\u00a5\" + item.getTotal())\n            );\n            return layout;\n        }));\n\n        \/\/ \u30ab\u30fc\u30c8\u5408\u8a08\n        H4 total = new H4(\"\u5408\u8a08: \u00a5\" + cartService.getTotal());\n\n        Button checkout = new Button(\n            \"\u30ec\u30b8\u306b\u9032\u3080\",\n            e -&gt; proceedToCheckout()\n        );\n\n        cartLayout.add(cartTitle, cartItems, total, checkout);\n        return cartLayout;\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-23\">\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u3067\u306e\u7d71\u5408\u4f8b<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vaadin\u3092\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u306b\u7d71\u5408\u3057\u305f\u4f8b\u3092\u793a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Route(\"\")\npublic class ServiceDashboardView extends VerticalLayout {\n    private final ServiceRegistry serviceRegistry;\n    private final MetricsService metricsService;\n\n    public ServiceDashboardView(\n            ServiceRegistry serviceRegistry,\n            MetricsService metricsService) {\n        this.serviceRegistry = serviceRegistry;\n        this.metricsService = metricsService;\n\n        \/\/ \u30b5\u30fc\u30d3\u30b9\u72b6\u614b\u306e\u76e3\u8996\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\n        add(createServiceOverview());\n\n        \/\/ \u30e1\u30c8\u30ea\u30af\u30b9\u30c1\u30e3\u30fc\u30c8\u306e\u8868\u793a\n        add(createMetricsDisplay());\n\n        \/\/ API\u547c\u3073\u51fa\u3057\u7d71\u8a08\n        add(createApiStatistics());\n\n        \/\/ \u5b9a\u671f\u66f4\u65b0\u306e\u8a2d\u5b9a\n        setupPeriodicUpdate();\n    }\n\n    private Component createServiceOverview() {\n        Grid&lt;ServiceInstance&gt; grid = new Grid&lt;&gt;();\n\n        grid.addColumn(ServiceInstance::getName)\n            .setHeader(\"\u30b5\u30fc\u30d3\u30b9\u540d\");\n        grid.addColumn(ServiceInstance::getStatus)\n            .setHeader(\"\u72b6\u614b\");\n        grid.addColumn(ServiceInstance::getUptime)\n            .setHeader(\"\u7a3c\u50cd\u6642\u9593\");\n        grid.addColumn(ServiceInstance::getLastHeartbeat)\n            .setHeader(\"\u6700\u7d42\u5fdc\u7b54\");\n\n        \/\/ \u30d8\u30eb\u30b9\u30c1\u30a7\u30c3\u30af\u30b9\u30c6\u30fc\u30bf\u30b9\u306e\u8868\u793a\n        grid.addColumn(new ComponentRenderer&lt;&gt;(instance -&gt; {\n            Icon icon = new Icon(instance.isHealthy() ?\n                VaadinIcon.CHECK_CIRCLE :\n                VaadinIcon.EXCLAMATION_CIRCLE);\n            icon.setColor(instance.isHealthy() ?\n                \"green\" : \"red\");\n            return icon;\n        })).setHeader(\"\u30d8\u30eb\u30b9\");\n\n        grid.setItems(serviceRegistry.getAllInstances());\n        return grid;\n    }\n\n    private Component createMetricsDisplay() {\n        VerticalLayout metricsLayout = new VerticalLayout();\n\n        \/\/ CPU\u4f7f\u7528\u7387\u30c1\u30e3\u30fc\u30c8\n        Chart cpuChart = new Chart(ChartType.LINE);\n        Configuration cpuConfig = cpuChart.getConfiguration();\n        cpuConfig.setTitle(\"CPU\u4f7f\u7528\u7387\");\n\n        XAxis xAxis = new XAxis();\n        xAxis.setCategories(getTimeCategories());\n        cpuConfig.addxAxis(xAxis);\n\n        YAxis yAxis = new YAxis();\n        yAxis.setTitle(\"\u4f7f\u7528\u7387 (%)\");\n        cpuConfig.addyAxis(yAxis);\n\n        DataSeries cpuSeries = new DataSeries();\n        cpuSeries.setData(metricsService.getCpuMetrics());\n        cpuConfig.addSeries(cpuSeries);\n\n        \/\/ \u30e1\u30e2\u30ea\u4f7f\u7528\u7387\u30c1\u30e3\u30fc\u30c8\n        Chart memoryChart = new Chart(ChartType.LINE);\n        \/\/ ... \u30e1\u30e2\u30ea\u30c1\u30e3\u30fc\u30c8\u306e\u8a2d\u5b9a\n\n        metricsLayout.add(cpuChart, memoryChart);\n        return metricsLayout;\n    }\n\n    private Component createApiStatistics() {\n        \/\/ API\u7d71\u8a08\u60c5\u5831\u306e\u8868\u793a\n        Grid&lt;ApiMetric&gt; grid = new Grid&lt;&gt;();\n\n        grid.addColumn(ApiMetric::getEndpoint)\n            .setHeader(\"\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\");\n        grid.addColumn(ApiMetric::getRequestCount)\n            .setHeader(\"\u30ea\u30af\u30a8\u30b9\u30c8\u6570\");\n        grid.addColumn(ApiMetric::getAverageResponseTime)\n            .setHeader(\"\u5e73\u5747\u5fdc\u7b54\u6642\u9593\");\n        grid.addColumn(ApiMetric::getErrorRate)\n            .setHeader(\"\u30a8\u30e9\u30fc\u7387\");\n\n        grid.setItems(metricsService.getApiMetrics());\n        return grid;\n    }\n\n    private void setupPeriodicUpdate() {\n        \/\/ 30\u79d2\u3054\u3068\u306b\u753b\u9762\u3092\u66f4\u65b0\n        UI.getCurrent().setPollInterval(30000);\n        UI.getCurrent().addPollListener(event -&gt; {\n            \/\/ \u30c7\u30fc\u30bf\u306e\u66f4\u65b0\u51e6\u7406\n            updateServiceStatus();\n            updateMetrics();\n            updateApiStatistics();\n        });\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u5b9f\u88c5\u4f8b\u304b\u3089\u3001Vaadin\u306e\u4e3b\u306a\u5229\u70b9\u304c\u660e\u78ba\u306b\u306a\u308a\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u751f\u7523\u6027\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u7d14\u7c8b\u306aJava\u30b3\u30fc\u30c9\u3067UI\u3092\u69cb\u7bc9\u53ef\u80fd<\/li>\n\n\n\n<li>\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u518d\u5229\u7528\u304c\u5bb9\u6613<\/li>\n\n\n\n<li>\u578b\u5b89\u5168\u306a\u958b\u767a\u74b0\u5883<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u4fdd\u5b88\u6027\u306e\u78ba\u4fdd<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u4e00\u8cab\u3057\u305f\u30b3\u30fc\u30c9\u30d9\u30fc\u30b9<\/li>\n\n\n\n<li>\u30c6\u30b9\u30c8\u304c\u5bb9\u6613<\/li>\n\n\n\n<li>\u30e2\u30b8\u30e5\u30fc\u30eb\u5316\u3055\u308c\u305f\u69cb\u9020<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30b9\u30b1\u30fc\u30e9\u30d3\u30ea\u30c6\u30a3<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30de\u30a4\u30af\u30ed\u30b5\u30fc\u30d3\u30b9\u3068\u306e\u89aa\u548c\u6027<\/li>\n\n\n\n<li>\u52b9\u7387\u7684\u306a\u30ea\u30bd\u30fc\u30b9\u7ba1\u7406<\/li>\n\n\n\n<li>\u67d4\u8edf\u306a\u62e1\u5f35\u6027<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3089\u306e\u4e8b\u4f8b\u3092\u53c2\u8003\u306b\u3001\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u8981\u4ef6\u306b\u5fdc\u3058\u3066\u9069\u5207\u306b\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3059\u308b\u3053\u3068\u3067\u3001\u52b9\u7387\u7684\u306a\u958b\u767a\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Warning: Undefined array key &#8220;is_admin&#8221; in \/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/ &#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1206","post","type-post","status-publish","format-standard","category-java","nothumb"],"_links":{"self":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/1206","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1206"}],"version-history":[{"count":1,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/1206\/revisions"}],"predecessor-version":[{"id":1207,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/1206\/revisions\/1207"}],"wp:attachment":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}